Java:空循环使用多少时间?

标签 java performance loops jit primitive

我正在尝试测试 Java 中自动装箱和拆箱的速度,但是当我尝试将其与基元上的空循环进行比较时,我注意到一件奇怪的事情。这个片段:

for (int j = 0; j < 10; j++) {
    long t = System.currentTimeMillis();
    for (int i = 0; i < 10000000; i++)
        ;
    t = System.currentTimeMillis() - t;
    System.out.print(t + " ");
}

每次我运行它,它都会返回相同的结果:

6 7 0 0 0 0 0 0 0 0

为什么前两个循环总是需要一些时间,然后其余的似乎被系统跳过了?

In this answer to this post,据说即时编译将能够优化这一点。但如果是这样,为什么前两个循环仍然需要一些时间?

最佳答案

JIT 在某段代码执行多次后触发。

HotSpot JVM 将尝试识别代码中的“热点”。热点是执行了很多次的代码片段。为此,JVM会“统计”各种指令的执行次数,当它判断出某 block 被频繁执行时,就会触发JIT。 (这是一个近似值,但以这种方式解释很容易理解)。

JIT(准时制)采用那段代码,并试图使其更快。

JIT 用于使您的代码运行得更快的技术有很多,但最常造成混淆​​的技术是:

  1. 它将尝试确定该段代码是否使用了其他地方未使用的变量(无用变量),并将其删除。
  2. 如果你多次获取和释放同一个锁(比如调用同一个对象的同步方法),它可以获取一次锁并在一个同步块(synchronized block)中完成所有调用
  3. 如果您访问未声明为 volatile 的对象成员,它可以决定对其进行优化(将值放入寄存器等),从而在多线程代码中产生奇怪的结果。
  4. 它将内联方法,以避免调用的成本。
  5. 它将字节码翻译成机器码。
  6. 如果循环完全无用,则可以将其完全删除。

因此,对您的问题的正确答案是,一个空循环在经过 JIT 后,不需要时间来执行……很可能不再存在了。

同样,还有许多其他优化,但根据我的经验,这些是最令人头疼的优化之一。

此外,JIT 在任何新版本的 Java 中都得到了改进,有时它甚至会因平台而有所不同(因为它在某种程度上是特定于平台的)。 JIT 完成的优化很难理解,因为您通常无法使用 javap 和检查字节码找到它们,即使在最新版本的 Java 中,其中一些优化已直接移至编译器(例如,自 Java 6 以来,编译器是能够检测并警告未使用的局部变量和私有(private)方法)。

如果你正在编写一些循环来测试某些东西,通常最好将循环放在一个方法中,在计时之前调用该方法几次,给它一个“加速”回合,然后执行定时循环。

这通常会在像您这样的简单程序中触发 JIT,即使不能保证它会实际触发(或者它甚至存在于特定平台上)也是如此。

如果你想对 JIT 或非 JIT 计时产生偏执(我做过):进行第一轮,为循环的每次执行计时,并等待计时稳定(例如,与平均值的差异小于 10% ),然后从您的“真实”时间开始。

关于Java:空循环使用多少时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7271147/

相关文章:

java - 当我将扫描仪对象分配给变量时程序崩溃

sql - 性能差异 : select top 1 order by vs. select min(val)

Python 字符串连接成语。需要澄清。

c++ - 前或后测试循环?

python - 在python循环中退一步进一步

java - 我的 NetBeans 导入项目无法在其他计算机上运行?

java - 其余 Jersey json 编码

python - 检查输入是否是 python 中的单个字母

java - 我如何在 Java 中比较字符串?

mysql - 优化大量更新查询