【问题标题】:JVM smart enought to optimize vararg array?JAVA 足够聪明以优化可变参数数组?
【发布时间】:2017-09-18 21:50:33
【问题描述】:

鉴于我们有这样的方法,并且我们希望尽可能快且内存效率高。 JVM 是否可能会足够聪明地将其优化为简单的字符串构建器追加,避免为可变参数创建 Object[] 并避免将原语自动装箱到该对象数组的 Object 中?

protected String stringId(Object... things) {
    final StringBuilder sb = new StringBuilder();

    for (Object thing : things) {
        if(sb.length() > 0) {
            sb.append('-');
        }
        sb.append(String.valueOf(thing));
    }

    return sb.toString();
}

【问题讨论】:

  • 在底层,可变参数一个数组;它只是语法糖。
  • 可变参数是语法糖,总是创建一个新数组。由于您的参数是一个对象数组,因此将始终涉及自动装箱。
  • 我不知道哪些 JVM(如果有的话)会尝试这种优化。我不认为它会,即使它会,它也可能只有在对这个方法的调用被内联时才会发生。内联取决于调用站点,并且在同一程序的运行中很容易发生变化。
  • @Mike Strobel:确实,尤其是在调用站点上也发生数组创建时。如果没有内联,就不可能在调用点得出结论该数组将纯粹是临时的。

标签: java performance jvm variadic-functions jit


【解决方案1】:

保存变量参数的临时数组是在调用站点创建的,每个调用站点将单独优化,并且可能忽略或不忽略对象分配。它需要将您的方法内联给调用者,以允许优化器证明该数组是纯粹临时的,即不会转义。

但是,无论是否发生,都无关紧要。在未优化的执行场景中,您有至少五个对象实例的基本占用空间,即可变参数数组、StringBuilder 及其后备数组以及结果String 及其后备数组。然后,对于每个还不是String 或特殊处理值(如nullboolean)的参数,调用String.valueOf(thing) 可能会在之前返回一个新的String 实例和一个新的后备数组附加到StringBuilder

此外,StringBuilder 的后备数组以 16 个字符的默认容量开始,每次容量用完时都会被更大的数组替换。

如前所述,这只是针对未优化的执行场景,优化器会在这些操作中找到很多优化机会,这些优化机会比为 varargs 参数创建的唯一数组实例的影响要大得多。这也适用于需要自动装箱的值。这种自动装箱也发生在调用者身上,并且受到专门针对自动装箱的优化。对于某些值,每次装箱时甚至必须对同一个对象求值。

请注意,经常被忽视的实际费用在不同的地方。例如,将数值转换为十进制表示比将这些值包装到轻量级 Integer 中要昂贵得多。 Double 对象。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-02-04
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    • 2011-11-09
    • 2015-05-21
    相关资源
    最近更新 更多