【发布时间】:2014-01-06 22:48:27
【问题描述】:
我最近在 Java 中发现了“assert”语句,并且在我调试软件时一直在乱扔我的软件。我最初的直觉是避免仅仅为了处理断言语句而制作控制流语句,但后来我意识到这些控制语句可能会在生产构建期间被删除,因为它们的块是空的。我的印象是它们会被 JIT 编译器消除。
不幸的是,我模糊地回忆了 JIT 编译器的工作原理,并且找不到合适的文档。我能找到的最好的是 IBM 优化过程的 brief outline。
在我养成实施基于断言的测试的习惯之前,我想知道是否有最佳实践来最大程度地减少它们对性能的影响。我不想执行一堆测试,却发现它们的集体影响是大大降低性能,即使它们的单独影响可以忽略不计。
谁能告诉我以下几行是否会拖累生产版本的性能(默认情况下禁用“断言”)?
for (T obj : Collection){
assert obj.someProperty();
}
另外,如果我是更复杂的东西,包括仅用于断言的短期对象,该怎么办?
TreeMap<Integer,T> map = new TreeMap<>();
int i = 0;
for (T obj : Collection){
map.put(i,obj);
assert obj.someProperty();
i++;
}
// assert something about map, then never use it again
或者是唯一作用是调用“assert”的方法?
提前致谢!
Oracle 文档中有关“assert”声明的相关摘录:
这些讨论了如何从类文件中删除断言,这并不是我所关心的。
从类文件程序员中删除所有断言跟踪 为资源受限的设备开发应用程序可能希望 完全从类文件中删除断言。虽然这使它 不可能在现场启用断言,它也减少了类 文件大小,可能会提高类加载性能。在 缺乏高质量的 JIT,可能会导致 占用空间并提高运行时性能。
断言工具不直接支持剥离 类文件中的断言。然而,断言语句可以是 与描述的“条件编译”成语一起使用 在 Java 语言规范中,使编译器能够消除 来自它生成的类文件的所有这些断言的痕迹:
静态最终布尔断言 = ... ; // false 以消除断言
如果(断言)断言;
在常见问题解答部分:
为什么不提供一个编译器标志来完全消除断言 从目标文件?这是一个坚定的要求,它是可能的 在现场启用断言,以增强可维护性。它会 还可以允许开发人员消除断言 在编译时来自目标文件。断言可以包含边 效果,尽管它们不应该,因此这样的标志可能会改变 程序在重要方面的行为。它被认为是好的 每个有效的 Java 只有一个语义相关联的事情 程序。此外,我们希望鼓励用户将断言留在对象中 文件,以便它们可以在现场启用。最后,规范要求 当一个类在它之前运行时,断言的行为就像启用一样 初始化。提供这些语义是不可能的,如果 断言从类文件中被剥离。但请注意, Java 中描述的标准“条件编译习语” 语言规范可用于实现此效果 真正想要它的开发人员。
【问题讨论】:
-
我不记得足够的细节来给出一个自信的答案,但我认为断言启用/禁用是在运行时,而不是在编译时。
-
@Brandon:感谢您的提醒。如果是这样的话,我想答案将是微不足道的。也许我需要阅读一些关于“断言”的内容。我正在添加问题的链接...
标签: java performance compiler-construction