ProGuard主页作为一项功能列出:
- 重新定位和预验证 Java 6 的现有类文件,以充分利用 Java 6 更快的类加载。
这在 Java 6 中指的是什么?
意义重大吗?
它是否会通过默认类加载器的同步方面对多线程造成的减速产生影响?
ProGuard主页作为一项功能列出:
这在 Java 6 中指的是什么?
意义重大吗?
它是否会通过默认类加载器的同步方面对多线程造成的减速产生影响?
Java 6 编译器将预验证信息添加到类文件中
查看Java Virtual Machine Specification Verification by Type Checking部分:
如果 Java 虚拟机实现尝试对 50.0 版本的类文件执行类型推断验证,则必须在类型检查验证失败的所有情况下执行此操作。
这意味着 Java 虚拟机实现不能选择在一种情况下而不是在另一种情况下诉诸类型推断。它必须要么拒绝不通过类型检查验证的类文件,要么在类型检查失败时始终故障转移到类型推断验证器。
类型检查器需要具有 Code 属性的每个方法的堆栈映射帧列表。类型检查器读取每个此类方法的堆栈映射帧,并使用这些映射生成 Code 属性中指令的类型安全性证明。
从 Java 6 开始,类文件 50.0 及更高版本,JVM 可以在类文件验证期间使用类型检查或类型推断。在尝试了解性能优势之前,什么是类型检查和类型推断?这篇论文,面向对象编程语言的类型检查和类型推断指出:
类型系统是编程语言的重要组成部分。完全依赖运行时类型检查的语言提供了高度的灵活性,但通常必须为此牺牲性能。
来自维基百科的类型推断:
类型推断是在编译时自动部分或全部推断出表达式类型的能力。[...]
为了获得推断表达式类型所需的信息,编译器要么将这些信息收集为聚合并随后减少为其子表达式提供的类型注释,要么通过对各种原子值类型的隐式理解 [... ]。
OpenJDK HotSport 运行时概述很好地解释了它:
目前有两种分析字节码的方法,以确定每条指令将出现的操作数的类型和数量。传统方法称为“类型推断”,通过对每个字节码进行抽象解释并在分支目标或异常句柄处合并类型状态来进行操作。分析迭代字节码,直到找到类型的稳定状态。如果找不到稳定状态,或者结果类型违反了某些字节码约束,则抛出 VerifyError。[...]
JDK6 中新增了第二种验证方法,称为“类型验证”。在此方法中,Java 编译器通过代码属性 StackMapTable 为每个分支或异常目标提供稳态类型信息。StackMapTable 由许多堆栈映射帧组成,每个堆栈映射帧都指示表达式堆栈上的项的类型以及方法中某个偏移处的局部变量中的项的类型。JVM然后只需要执行一次通过字节码来验证类型的正确性来验证字节码。[...]
类型检查是指 JVM 可以通过类文件来验证类型系统;类型推断需要多次传递。这是显着的性能节省吗?它可能与您在应用程序中拥有的类总数以及您拥有的小于 50.0 (Java 6) 和 50.0 及更大的类文件的数量有关。如果您的应用程序不是性能关键型应用程序,我不会担心;如果是,那么您可以运行一些基准来比较将应用程序编译为 Java 5 和 Java 6 类文件时的性能差异。
根据此 Java 6 白皮书,改进之处在于:
Java 虚拟机的引导和扩展类加载器已得到增强,以改善 Java 应用程序的冷启动时间。在 Java SE 6 之前,打开系统 jar 文件会导致 Java 虚拟机读取一个 1 兆字节的 ZIP 索引文件,当文件不在磁盘缓存中时,该文件会转换为大量磁盘查找活动。启用“类数据共享”后,Java 虚拟机现在提供了一个“元索引”文件(位于 jre/lib 中),其中包含有关哪些包(或包前缀)包含在哪些 jar 文件中的高级信息.
这有助于 JVM 在加载 Java 应用程序类时避免打开引导和扩展类路径上的所有 jar 文件。
这种特殊的改进不应该对正在运行的程序产生任何影响,因为系统 jar 中的类已经被加载了。它只会影响应用程序的第一次启动时间。
(回答我自己的问题)
我在 ProGuard 网站上的“什么是预验证? ”部分找到了大部分答案:
加载类文件时,类加载器会对字节码进行一些复杂的验证。这种分析确保代码不会意外或故意突破虚拟机的沙箱。[...]Java 6 引入了拆分验证。[...]Java 6 编译器将预验证信息添加到类文件([...]
StackMapTable
属性),以简化类加载器的实际验证步骤。然后可以以更节省内存的方式更快地加载类文件。
这似乎与并发无关。
所以剩下的一个问题是:“它重要吗? ”,这在很大程度上被回答为“否”: