【问题标题】:Does boxing cause performance issues?拳击会导致性能问题吗?
【发布时间】:2011-12-12 22:43:40
【问题描述】:

我正在做一个项目,我们正在生产一种可编译为 java 的语言。我们使用的框架 (xtext) 在其生成的代码中大量使用了装箱。 具体来说,如果你有这样的声明:

int i = 1;
int j = 2;
int k = i + j;

那么编译后的代码如下:

IntegerExtensions.operator_plus(((Integer)i), ((Integer)j))

现在,在我正在进行的项目中,在某些情况下,特定的基本二进制操作将非常普遍(尤其是增量和比较)。

我的问题是:这会是性能方面的问题,还是 JIT(或类似智能 JVM 功能)会简单地意识到发生了什么并解决所有问题?

发帖前请阅读:我不想收到回复说“你不应该关心,让它可读”。这段代码是生成的,我根本不关心生成代码的可读性。我真正关心的是我们不会因此而对性能造成重大影响。

谢谢

【问题讨论】:

  • 你说编译后的代码,是指编译进你的框架还是编译成字节码?
  • 拳击比不拳击贵。有关系吗? (这是这里唯一真正的问题。)嗯,“这取决于”...另外,为什么编译后的代码看起来像这样? :) 有一个iadd native java 字节码...
  • @glowcodeer:当我说编译代码时,我的意思是从我的语言中提取并编译成 .java 文件。
  • @pst:我不确定为什么代码看起来像这样,但我假设在一般情况下它背后有某种原因。至于“这有关系吗?”,这实际上不是问题——问题是“它总是更贵吗?” - 看看我提到的即时编译,以及我对约翰回答的评论。
  • @Jeff 具体答案仍然是:“可能是”,一般答案是“视情况而定”。仅仅因为不一定创建新对象并不意味着它在字节码 JIT 代码中具有相同的路径。找到一个病态的理想案例,说明它在哪里被有效地 JIT 删除了——假设存在这样的案例——并没有帮助。只有复制真实用法的性能分析才能“正确”回答这个问题。

标签: java performance jit boxing xtext


【解决方案1】:

这实际上会产生影响。当转换为Integer 时,它将使用Integer.valueOf(int n) 方法将int 转换为Integer。此方法将检查该值是否在缓存范围内(-128 到 127),如果不在则创建 new Integer(n)

影响的大小可能很大也可能很小,您必须自己测试。

【讨论】:

  • 那么JIT或类似的东西不可能意识到拳击完全没有意义并完全摆脱它吗?这些盒子非常频繁地发生,在基本相同的情况下,并且不会停留很长时间,我真的希望 JVM 能够为我完成我的工作。
  • 据我所知,JIT 不会绕过装箱操作(如果可以的话,那将是一种运行时优化算法)。
  • 使用-XX:+EscapeAnalysis 可以删除创建的自动装箱对象。实际上,我从未见过 Sun/Oracle JVM 放弃对象创建。开始分析您的应用程序以确定它是否重要,然后再担心它会更有用。
【解决方案2】:

要说它导致性能问题取决于您所说的问题。而你所说的问题可能取决于代码将解决什么样的问题。

this answer 中有一个部分对此进行了总结,还提供了 Autoboxing 指南的链接,其中提到:

科学计算或其他性能敏感的数字代码不适合使用自动装箱和拆箱。

这是specific example with benchmarks focusing on int/Integer autoboxing

简单的问题:int/Integer 类型的自动装箱有多贵?

简单的答案:每个拳击 15 纳秒。

【讨论】:

    【解决方案3】:

    我的一些观察:

    1. 装箱通常确实会降低应用程序的性能。它的显着程度取决于所实现算法的性质。是否值得修复,在哪里只有分析器和您的预期成本效益比才能告诉您。

    2. 装箱通常确实会增加应用程序的内存使用量。就我而言,这非常很重要——可能比性能更重要。

      Java 中的int 在 32 位范围内占用 4 到 8 个字节(取决于 JVM 实现)的内存。 Integer 在 64 位系统上将占用 20 到 24 个字节 - 您仍然需要对它的引用。对于处理大型数组的应用程序,可以轻松地将其内存需求增加四倍 (x4),甚至更糟。

      在这种情况下,拳击可以区分“它可以工作”和“它不工作” - 在给定的计算机上您只能拥有这么多的内存。性能甚至没有进入讨论范围,尽管内存不足的应用程序通常也会变慢。

    也就是说,对象确实有一个有用的优势:使用null有一种本地方式来表示“不存在价值”。

    【讨论】:

    • 我想,虽然内存可能是个问题,但 GC 应该能够处理这个问题。我正在处理的情况是对象在很短的时间内被装箱,因此 GC 应该能够非常快速地丢弃生成的对象。持久化状态仍然保持为 int,只有在需要发生某些事情时才会被装箱。
    【解决方案4】:

    简单地说:测试一下。

    制作一个简单示例的两个版本并测量其花费的时间。然后您就会知道性能的确切差异以及您是否负担得起。

    【讨论】:

    • 是的。我们应该自己谷歌并测试一切。我们不需要在 SO 上发臭的问题。
    猜你喜欢
    • 2015-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-10
    • 2017-04-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多