【问题标题】:Does primitive wrapper instantiation cause memory allocation in JDK 1.6原始包装器实例化是否会导致 JDK 1.6 中的内存分配
【发布时间】:2010-07-24 00:20:17
【问题描述】:

来自 PMD:

IntegerInstantiation:在 JDK 1.5 中,调用 new Integer() 会导致内存分配。 Integer.valueOf() 对内存更友好。

ByteInstantiation:在 JDK 1.5 中,调用 new Byte() 会导致内存分配。 Byte.valueOf() 对内存更友好。

ShortInstantiation:在 JDK 1.5 中,调用 new Short() 会导致内存分配。 Short.valueOf() 对内存更友好。

LongInstantiation:在 JDK 1.5 中,调用 new Long() 会导致内存分配。 Long.valueOf() 对内存更友好。

这同样适用于 JDK 1.6 吗?我只是想知道编译器或 jvm 是否将其优化为各自的 valueof 方法。

【问题讨论】:

    标签: jvm java jdk1.6


    【解决方案1】:

    理论上,编译器可以优化一个案例子集,其中(例如)使用new Integer(n)而不是推荐的Integer.valueOf(n)

    首先,我们应该注意,只有当编译器可以保证包装对象永远不会与使用==!= 的其他对象进行比较时,才能应用优化。 (如果发生这种情况,那么优化会改变包装对象的语义,使得“==”和“!=”的行为方式与 JLS 相悖。)

    鉴于此,这种优化不太可能值得实施:

    1. 优化只会帮助那些忽略 javadoc 等建议的编写不佳的应用程序。对于编写良好的应用程序,测试是否可以应用优化只会减慢优化器的速度;例如JIT 编译器。

    2. 即使对于编写不佳的应用程序,允许优化的位置的限制意味着对new Integer(n) 的实际调用很少有资格进行优化。在大多数情况下,跟踪可能使用new 表达式创建的包装器的所有位置的成本太高。如果您在图片中包含反射,则除了局部变量之外几乎不可能进行跟踪。由于原始包装器的大多数用途都需要将它们放入集合中,因此很容易看出(通过实际的优化器)几乎不会允许优化。

    3. 即使在实际应用优化的情况下,它也只会在有限范围内对n 的值有所帮助。例如,为大的n 调用Integer.valueOf(n) 将始终创建一个新对象。

    【讨论】:

      【解决方案2】:

      这也适用于 Java 6。使用 Java 6 尝试以下方法来证明这一点:

      System.out.println(new Integer(3) == new Integer(3));
      System.out.println(Integer.valueOf(3) == Integer.valueOf(3));
      
      System.out.println(new Long(3) == new Long(3));
      System.out.println(Long.valueOf(3) == Long.valueOf(3));
      
      System.out.println(new Byte((byte)3) == new Byte((byte)3));
      System.out.println(Byte.valueOf((byte)3) == Byte.valueOf((byte)3));
      

      但是,正如预期的那样,如果数字很大,优化就会关闭。

      【讨论】:

        【解决方案3】:

        这同样适用于 Java SE 6。一般来说,很难优化新对象的创建。可以保证,比如new Integer(42) != new Integer(42)。在某些情况下,有可能完全不需要获取对象,但我相信在撰写本文时,HotSpot 生产版本中已禁用所有这些。

        【讨论】:

          【解决方案4】:

          大多数时候这并不重要。除非您已确定您正在运行一段被多次调用的关键代码(例如 10K 或更多),否则它可能不会产生太大影响。

          如果有疑问,假设编译器没有进行优化。它实际上很少。然而,JVM 可以做很多优化,但消除创建对象的需要并不是其中之一。一般的假设是对象分配在大多数情况下都足够快。

          注意:只运行几次(默认情况下小于 10K 时间)的代码甚至不会完全编译为本机代码,这可能会比对象分配更慢您的代码。

          【讨论】:

            【解决方案5】:

            在最近的带有转义分析和标量替换的 jvm 上,当变量的范围仅限于一个方法或块时,new Integer() 实际上可能比Integer.valueOf() 更快。有关更多详细信息,请参阅Autoboxing versus manual boxing in Java

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-02-24
              • 1970-01-01
              相关资源
              最近更新 更多