JVM非确定性运行时间

JVM非确定性运行时间,jvm,Jvm,在2.8GHz linux计算机上,一个单线程程序运行一个5亿次迭代的循环通常需要大约400毫秒,偶尔也需要大约1200毫秒。这是在一个只测量循环经过时间的程序中观察到的。什么解释了这种可变性 import java.io.PrintWriter; import java.util.Date; public class Tester { public static void main(String[] args) { PrintWriter pw = new P

在2.8GHz linux计算机上,一个单线程程序运行一个5亿次迭代的循环通常需要大约400毫秒,偶尔也需要大约1200毫秒。这是在一个只测量循环经过时间的程序中观察到的。什么解释了这种可变性

import java.io.PrintWriter;
import java.util.Date;

public class Tester
{
    public static void main(String[] args)
    {
        PrintWriter pw = new PrintWriter(System.out, true);

        Date d0 = new Date();
        long t0 = d0.getTime();

        for (long i = 0; i < 500000000; i++)
            ;

        Date d1 = new Date();
        long t1 = d1.getTime();

        pw.format("%d\n", t1 - t0);   
    }
}
导入java.io.PrintWriter;
导入java.util.Date;
公共类测试员
{
公共静态void main(字符串[]args)
{
PrintWriter pw=新的PrintWriter(System.out,true);
日期d0=新日期();
longt0=d0.getTime();
对于(长i=0;i<500000000;i++)
;
日期d1=新日期();
longt1=d1.getTime();
格式(“%d\n”,t1-t0);
}
}

垃圾收集例程需要运行一段时间,即使您没有垃圾要收集

很容易假设,既然您不分配或取消引用内存,那么您就不需要收集垃圾;但是,垃圾收集例程是在独立线程中运行的,它不会检查代码中可能的流以确定是否应该运行

因此,垃圾收集例程启动并发现没有要收集的垃圾。这需要一些时间

此外,由于操作系统需要立即处理某些中断,您的程序(即,解释类的整个JVM)可能已经从CPU上调出。这甚至可以发生在多核系统中,具体取决于CPU的核心选择算法。CPU必须立即处理的项目示例包括将以太网内存缓冲区复制到系统内存(以防止数据包丢失)、捕获键盘输入等


简言之,如果你想让你的分析有意义,你必须对你的基准测试进行真正的统计,因为各种外部项目都会影响你运行程序的时间。

顺便说一句,这指出了使用System.gc()的一个原因,尽管人们似乎开始为不使用它而进行宗教斗争。我已经看到System.gc()导致我的程序效率降低(效率是工时除以运行时间)。但是,如果您需要半一致的执行时间,则绝对必须使用System.gc(),但如果您确定一致性有好处,就可以使用它。我的程序95%的时间都是无所事事的,所以我不关心效率。如果你真的想要一致的执行时间,你不需要经常调用System.gc()。您可以预先分配所需的所有对象,然后执行大量对象复制(而不是实例化)。通过请求垃圾收集(您不认为System.gc()实际上强制垃圾收集,是吗?)您可能会更频繁地运行垃圾收集器,但您肯定不能保证它。您也不能保证每次运行它所做的工作会更少。你唯一能保证的是,在完成它的工作后,它可能会释放更少的对象。“你也不能保证每次运行它都会做更少的工作。”我想你的意思是,我无法获得更好的一致性(每次运行的垃圾收集工作更少;比默认实现中没有自由使用System.gc()的最坏情况运行的意义更少)。如果事实上这就是你的意思,那么让我惊讶的是你是对的。现在我回到了第一步,试图获得一致性。