当前位置: 首页 > 知识库问答 >
问题:

围绕断言语句的迭代器会影响生产构建的性能吗?

漆雕和雅
2023-03-14

我最近在Java中发现了“assert”语句,并在调试软件时将它们乱放。我最初的直觉是避免仅仅为了处理断言语句而生成控制流语句,但后来我意识到这些控制语句可能在生产构建期间被删除,因为它们的块将是空的。我的印象是它们将被JIT编译器消除。

不幸的是,我对JIT编译器的工作原理记忆犹新,找不到合适的文档。我能找到的最好的东西就是IBM提供的优化过程的简要概述。

在我养成实现基于断言的测试的习惯之前,我想知道是否有最佳实践可以最大限度地减少它们对性能的影响。我不想实施一系列测试,结果却发现它们的集体效应会大大降低性能,即使它们单独的影响可以忽略不计。

你们中有谁能告诉我以下行是否会拖累生产构建的性能(默认情况下禁用了“断言”)?

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

或者一个唯一的效果是调用“断言”的方法?

提前谢谢!

Oracle“断言”声明文档的相关摘录:

这些讨论了如何从类文件中删除断言,这并不是我所关心的。

从类文件中删除断言的所有痕迹为资源受限设备开发应用程序的程序员可能希望完全从类文件中删除断言。虽然这使得无法在字段中启用断言,但它也减少了类文件的大小,可能会提高类加载性能。在缺乏高质量JIT的情况下,它可能会减少占用空间并提高运行时性能。

断言工具不直接支持从类文件中剥离断言。然而,assert语句可以与Java语言规范中描述的“条件编译”习惯用法结合使用,使编译器能够从其生成的类文件中消除这些断言的所有痕迹:

静态最终布尔断言=…;//假以消除断言

如果(断言)断言;

从常见问题部分:

为什么不提供一个编译器标志来完全消除对象文件中的断言?这是一个坚定的要求,即能够在现场启用断言,以增强可维护性。还可以允许开发人员在编译时消除对象文件中的断言。断言可以包含副作用,尽管它们不应该包含副作用,因此,这样的标志可以显著地改变程序的行为。每个有效的Java程序只有一个语义关联,这被视为一件好事。此外,我们希望鼓励用户在对象文件中保留断言,以便可以在字段中启用它们。最后,规范要求断言在类初始化之前运行时表现为启用。如果从类文件中剥离断言,则不可能提供这些语义。但是,请注意,Java语言规范中描述的标准“条件编译习惯用法”可以用于真正需要它的开发人员实现这种效果。

共有2个答案

岳京
2023-03-14

你们中有谁能告诉我以下行是否会拖累生产构建的性能(默认情况下禁用了“断言”)?

无论断言是打开还是关闭,断言循环都将运行(即,不管断言是字节码的一部分,断言在运行代码时启用)。但是,我不会担心第一个代码片段的性能;JIT可能会意识到循环没有做任何事情,并在早期处理它。

另外,如果我是更复杂的东西,包括只用于断言的短期对象,该怎么办?

像你的第二个片段这样的东西更难确定——最好的办法可能是自己计时,尽管在大多数情况下,我认为它也不会有明显的影响。

也许您可以使用一个“debug”标志,并将其用作:

static boolean debug = true;

if (debug) {
    // loop here
}
冉高寒
2023-03-14

您可以在断言中进行方法调用,因此我更喜欢以下语法:

private static boolean testSomePropertyTrue(Collection<T> collection) {
    boolean test = true;
    for (T obj : collection){
        test = test && obj.someProperty();
    }
    return test;
}

...

assert testSomePropertyTrue(collection);

这使得JIT优化的代码不会有任何含糊之处,当断言被启用时,将执行相同的不变检查。

如前所述,无论是否启用断言,您的第二个示例都将始终创建树映射。将整个内容包装在一个函数中,并将其作为单个断言进行计算,将在运行时完全消除该代码路径。

正如这个问题的另一个答案所暗示的,断言将留下字节码,不管它们是否被启用,但是使用上面显示的样式将决定性地阻止这些代码路径执行,除非断言被启用。

 类似资料:
  • 使用时,是否有需要考虑的性能影响? 我正在编写一个从目录检索文件的查询,这就是查询: 那么,在决定进行这样的转换时,是否应该考虑某种性能影响--还是只在处理大量文件时才考虑?这是一个可以忽略不计的转换吗?

  • 问题内容: 所以我有一个查询,在SELECT中需要一堆CASE语句。这不是原始的设计,而是折衷的一部分。 因此查询看起来像这样: 我的问题是,将所有这些CASE语句更改为直接列引用会对性能产生什么影响。 换句话说:如果我将每个CASE语句更改为一个列名,并从查询中删除了所有CASE语句,那么会对性能产生很大影响,为什么? 我正在对此进行测试,因此我可以弄清楚性能是否受到影响,但是我对WHY的细节也

  • 问题内容: varchar列上的索引是否会使查询运行缓慢?我可以将其设为int。而且我不需要做LIKE%比较。 问题答案: varchar列上的索引是否会使查询运行缓慢? 不,不是的。 如果优化器决定使用索引,则查询将运行得更快。 该表上的s / s / s会变慢,但不太可能引起注意。 我不需要做LIKE%比较 请注意,使用: …将 不 使用索引,但以下内容将: 关键是在字符串的左侧使用通配符,这

  • 本文向大家介绍C#中Try-Catch语句真的影响程序性能吗?,包括了C#中Try-Catch语句真的影响程序性能吗?的使用技巧和注意事项,需要的朋友参考一下 很多帖子都分析过Try-Catch的机制,以及其对性能的影响。 但是并没有证据证明,Try-Catch过于损耗了系统的性能,尤其是在托管环境下。记得园子里有位网友使用StopWatch分析过Try-Catch在不同情况下,与无Try-Cat

  • 今天,我发现在添加了一些不相关的代码后,示例代码的速度降低了50%。调试后,我发现问题出在循环对齐中。根据循环代码的位置,有不同的执行时间,例如: 我以前没想到代码对齐会产生如此大的影响。我认为我的编译器足够聪明,可以正确对齐代码。 到底是什么导致了执行时间的如此大的差异?(我想是一些处理器架构细节)。 我用Visual Studio 2019在发布模式下编译的测试程序,并在Windows 10上

  • 问题内容: 在浏览器中,缩小和隐藏或加载异步JavaScript会对性能产生积极影响。在Node.js中运行的代码是否也是如此? 如Example那样,过多的注释和为实例化的类的属性使用长名称通常会严重影响性能和内存使用吗? 问题答案: 是的 ,它可以提高编译时的性能,但是编译时对您的整个过程生命周期而言无关紧要,因此无关紧要。唯一的区别是,如果您出于某种奇怪的原因而不断地启动和停止节点程序,那么