启动 java 应用程序时使用 -noverify

Posted

技术标签:

【中文标题】启动 java 应用程序时使用 -noverify【英文标题】:Use of -noverify when launching java apps 【发布时间】:2010-09-22 23:21:07 【问题描述】:

我看到许多应用程序在加载时使用仪器类并以-javaagent 作为参数,还将-noverify 放入命令行。

Java 文档说-noverify 关闭了类验证。

但是为什么有人想要关闭验证,即使他们正在检测类?

【问题讨论】:

【参考方案1】:

启动时间,我会说。加载类时验证类是否正确需要一些时间。由于类可能会以惰性方式加载(不是在应用启动时,而是在第一次使用时),这可能会导致意外和不希望的运行时延迟。

其实类一般不需要检查。编译器不会发出任何无效的字节码或类构造。验证的原因是该课程可能建立在一个系统上,在线托管并通过未受保护的互联网传输给您。在这条路径上,恶意攻击者可能会修改字节码并创建编译器可能永远不会创建的东西;可能会使 JVM 崩溃或可能绕过安全限制的东西。因此,在使用该类之前对其进行验证。如果这是本地应用程序,通常不需要再次检查字节码。

【讨论】:

如果有人在 2013+ 年对这个答案感到疑惑,请检查 Arian 的答案,因为这个答案不正确。 github.com/spring-projects/spring-loaded#readme @Pavel 我的回答没有错。仅仅因为存在禁用字节码检查是一个好主意的另一个原因,这不会使答案变得不那么正确。 SpringLoad 只是一个现有的 JavaAgent,仅仅因为它可能产生无效的字节码并不意味着所有的 JavaAgent 都会这样做,因为在输入无效字节码时没有 JVM 必须正常工作,这就是为什么世界上大多数软件只产生有效的byte,使 Arian 的论点无效。 不要误会我的意思——你已经很好地解释了noverify 的工作原理以及它为什么可以加速类加载。然而,这个问题是关于它与javaagent 的联系的非常具体的问题。你是在说吗? JRebel 在每个集成手册中都使用这个 JVM 参数只是为了性能? 这个问题也不是关于JRebel或者SpringLoad的,那么为什么JRebel或者SpringLoad使用它有什么关联呢?【参考方案2】:

当它与-javaagent 一起使用时,很可能不是出于性能原因,而是因为代理故意创建“无效”字节码。

需要注意的是,无效的字节码可能仍然可以正常执行,因为某些验证规则非常严格。例如,在调用超级构造函数之前,不能在构造函数中访问this,因为此时尚未初始化变量。但是您可能还想做其他事情(请参阅 JRebel 示例)。然后,您使用-noverify 来规避该规则。

【讨论】:

【参考方案3】:

调试!事实上,这就是我现在正在做的事情,以及我是如何偶然发现这个问题的。在 Terracotta,我们做了很多字节码检测,有时在调试类适配器时关闭验证器会有所帮助,这样我们就可以看到它们在运行时失败的确切位置。

你说得对,我们希望验证器继续投入生产。

【讨论】:

【参考方案4】:

在没有-noverify 的情况下使用 JRebel 会在启动时给出这个警告:

JRebel:缺少“-noverify”,将无法启用更改/添加/删除构造函数!

看来-noverify 允许字节码重新检测来完成一些原本不可能的事情。

【讨论】:

【参考方案5】:

启动时间曾经是个问题。但是,验证器现在速度更快,处理器也一样。默认情况下,使用 JDK6 javac 编译的代码将包含额外信息以加快验证程序步骤。 Apache Harmony 只是使用了更快的验证算法。

一些非常旧的 javac 版本产生了不正确的字节码。实际上,Sun 插件仍然包含修复代码,以验证一些损坏的类文件。

【讨论】:

【参考方案6】:

JAVA 6 中引入的新验证器对于代码操作来说处理起来非常复杂。

看看这个: http://chrononsystems.com/blog/java-7-design-flaw-leads-to-huge-backward-step-for-the-jvm

以及相关的错误报告: http://bugs.sun.com/view_bug.do?bug_id=8009595

【讨论】:

以上是关于启动 java 应用程序时使用 -noverify的主要内容,如果未能解决你的问题,请参考以下文章

使用 GraphQL Java 工具时 Spring Boot 应用程序无法启动

使用 minifyEnabled true 启动应用程序时 FirebaseInitProvider.onCreate 中的 java.lang.IncompatibleClassChangeErro

使用 minifyEnabled true 启动应用程序时 FirebaseInitProvider.onCreate 中的 java.lang.IncompatibleClassChangeErro

使用 AWS 自动缩放自动启动 java 服务器程序

java 中常用缓存cache机制的实现 程序启动自动加载时怎么实现的

保存我的唯一 ID(字符串)并稍后在我重新启动 Java 应用程序时检索它