2016-03-03 86 views
-2

考虑到下面的完整源代码,请解释为什么Eclipse中此程序的每次执行结果为time,do1()大于time,do2() 2〜3毫秒。JVM - 速度性能问题

JVM是否需要“预热”?

import java.util.concurrent.atomic.AtomicInteger; 
import java.util.stream.IntStream; 

public class Question { 
    public static void main(String[] args) { 
     do1(); 
     do2(); 
    } 

    public static void do1() { 
     O obj = new O(); 
     Thread t = new Thread(() -> IntStream.range(0, 100000) 
        .forEach(e -> obj.incrementN())); 

     long start = System.currentTimeMillis(); 

     t.start(); 

     try { 
      t.join(); 
     } catch (InterruptedException e1) { 

     } 

     float time = (System.currentTimeMillis()-start)/1000F; 

     System.out.println(time); 
     System.out.println(obj); 
     System.out.println(); 
    } 

    public static void do2() { 
     O obj = new O(); 
     Thread t = new Thread(() -> IntStream.range(0, 100000) 
        .forEach(e -> obj.incrementN())); 

     long start = System.currentTimeMillis(); 

     t.start(); 

     try { 
      t.join(); 
     } catch (InterruptedException e1) { 

     } 

     float time = (System.currentTimeMillis()-start)/1000F; 

     System.out.println(time); 
     System.out.println(obj); 
    } 
} 

class O { 
    private AtomicInteger n = new AtomicInteger(0); 

    public void incrementN() { 
     n.getAndIncrement(); 
    } 

    @Override 
    public String toString() { 
     return ""+n.get(); 
    } 
} 

输出示例:

0.003 
100000 

0.001 
100000 
+1

如果你这样做了1000次,然后拿出平均结果,这样会更准确。这可能只是随机性。 – Gendarme

+2

是的,JVM需要预热,因为大量使用的代码通过JIT系统编译为本机代码。 – Xvolks

+0

它只是一次性的结果,平均可以给出更准确的结果。 它可以加载在do1()中完成一次的类O的时间,然后在do2()中不花费时间。 –

回答

0

这的确是一个太短的时间跨度,以真正确定是什么原因导致DO1()来执行比DO2长()。

一些因素可以是:

  • 垃圾收集器踢(创建例如你O和T对象,指针到其存储位置(在栈上)被破坏时,方法DO1()留下,但记忆本身是由垃圾收集器释放)

  • Eclipse中做了一些分析的东西在两者之间(测量的变量,时间或东西)

  • 如你所说,在JVM可能也做一些热身的东西。

  • 不利的CPU调度。这可能是因为DO1()得到一些更多的CPU时间超过DO2(),无论出于何种原因

调用DO1()(或休眠)之前,你可以做一些东西,然后调用DO1(),然后再次等待并调用do2()并再次测量。或者你可以增加do1()和do2()消耗的时间量。另外,你的do1()和do2()方法(do1()中的name和println除外)完全相同,所以当你只调用do1()2次时会发生什么?