2014-02-22 60 views
4

javac或JIT是否优化不必要的自动装箱?假设我们有这段代码。JVM是否优化了不必要的自动装箱?

for(int i=0; i<100000; i++) { 
    f(i); 
} 

void f(Integer i) { 
    System.out.println(i); 
} 

这段代码如何得到优化?我猜f将内联,但不必要的拳击int(它不会被修改,永远不会是null)。我们假设该方法不是从任何其他代码片段调用的。如果方法签名是
void f(final Integer i)会有什么区别?

回答

2

JVM可以自由地做任何它喜欢的优化,所以有可能某些JVM会优化它。

这是不好的做法,假设它会,但是对于每个JVM来说,可能有几个不这样做。

只要改变方法,因为它使用它里面接受拳击同级别的类型..

+0

嗯,这是我在技术面试中遇到的一个问题,询问的人相当期待具体的答案。我们在谈论HotSpot JVM。我理解你的观点并同意。 – Sebastian

1

当你看看这个:

public class a 
{ 
    public static void main(String[] args) 
    { 
     for (int i = 0; i < 100000; i++) 
      f(i); 
    } 

    public static void f(Integer i) 
    { 
     System.out.println(i); 
    } 
} 

,看看它是什么样子调用javac a.java && javap -c a后,你会得到

Compiled from "a.java" 
public class a { 
    public a(); 
    Code: 
     0: aload_0  
     1: invokespecial #1     // Method java/lang/Object."<init>":()V 
     4: return   

    public static void main(java.lang.String[]); 
    Code: 
     0: iconst_0  
     1: istore_1  
     2: iload_1  
     3: ldc   #2     // int 100000 
     5: if_icmpge  21 
     8: iload_1  
     9: invokestatic #3     // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 
     12: invokestatic #4     // Method f:(Ljava/lang/Integer;)V 
     15: iinc   1, 1 
     18: goto   2 
     21: return   

    public static void f(java.lang.Integer); 
    Code: 
     0: getstatic  #5     // Field java/lang/System.out:Ljava/io/PrintStream; 
     3: aload_0  
     4: invokevirtual #6     // Method java/io/PrintStream.println:(Ljava/lang/Object;)V 
     7: return   
} 

此字节码告诉我们Integer.valueOf()被称为(main 9:),因此没有优化德在这种情况下,在编译级别。然而,正如@Tim B指出的那样,JVM内发生的事情是另一个无法预测的问题。最好假定最坏的情况 - JVM不会优化它。

+6

'javac'几乎没有进行优化,读取字节码并不能很好地测试代码在优化时的功能。 –

4

在OpenJDK和热点JVM 5 - 8不优化他们离开,除非他们不使用(即使在当时并不总是)

然而,有透视感,当你问这些是非常重要的问题或回答他们。与将数字转换为String的代码(无论如何,JVM执行此操作的方式)相比,Autoboixing是微不足道的,与写入控制台相比,这是微不足道的。如果取出System.out.println(),这将节省99.99%的时间,所以在这里担心自动装箱会担心错误的事情。

在您的具体情况中,由于PrintStream.println(Object)被调用,因此无法优化自动装箱方式。 JVM通常不理解库所做的事情,也不能假定调用PrintStream.println(int)会做同样的事情。

+0

那么记忆效率呢?如果在每次调用自动装箱发生时都会有大约99873(100000-127)个Integer实例被不必要地创建。我不同意我不应该担心自动装箱。但是我现在看到为什么这种情况不会被优化,因为println(Object)的调用。 – Sebastian

+2

@Sebastian是正确的,我并不是说它什么都不做,只是转换为文本的成本要高得多,写入屏幕的成本远高于此。尝试计算取出整数所取得的效果与取出整体所取得的结果之间的差异。你不需要测量它,差别非常大,你会看到差异。 –