Java:一个空循环需要多少时间?
我正在尝试测试 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
为什么前两个循环总是需要一些时间,然后其余的似乎只是被系统跳过?
在这篇文章的回答中,< /a> 据说 Just-In-Time 编译将能够优化这一点。但如果是这样,为什么前两个循环仍然需要一些时间?
I am trying to test the speed of autoboxing and unboxing in Java, but when I try to compare it against an empty loop on a primitive, I noticed one curious thing. This snippet:
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 + " ");
}
Every time I run this, it returns the same result:
6 7 0 0 0 0 0 0 0 0
Why does the first two loops always take some time, then the rest just seem to be skipped by the system?
In this answer to this post, it is said that Just-In-Time compilation will be able to optimize this away. But if so, why the first two loops still took some time?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
JIT 在某段代码被执行多次后触发。
HotSpot JVM 将尝试识别代码中的“热点”。热点是执行多次的代码片段。为此,JVM会“统计”各种指令的执行次数,当它确定某条指令被频繁执行时,就会触发JIT。 (这是一个近似值,但这样解释很容易理解)。
JIT(即时)获取该代码段,并尝试使其更快。
JIT 用于使代码运行得更快的技术有很多,但最常造成混乱的技术是:
所以,你的问题的正确答案是,一个空循环在被 JIT 后,不需要时间来执行......很可能已经不存在了。
同样,还有许多其他优化,但根据我的经验,这些是最令人头疼的优化。
此外,JIT 在 Java 的任何新版本中都得到了改进,有时甚至根据平台的不同而略有不同(因为它在某种程度上是特定于平台的)。 JIT 完成的优化很难理解,因为您通常无法使用 javap 和检查字节码找到它们,即使在最新版本的 Java 中,其中一些优化已直接移至编译器(例如,自 Java 6 以来,编译器是能够检测并警告未使用的局部变量和私有方法)。
如果您正在编写一些循环来测试某些内容,通常最好将循环放在方法中,在计时之前调用该方法几次,以使其“加速”一轮,然后执行定时循环。
这通常会在像您这样的简单程序中触发 JIT,即使不能保证它实际上会触发(或者甚至不能保证它存在于某个平台上)。
如果你想对 JIT 或非 JIT 计时感到偏执(我就是这么做的):进行第一轮,对循环的每次执行进行计时,并等到计时稳定(例如,与平均值的差异小于 10%),然后从你的“真实”时间开始。
JIT triggers AFTER a certain piece of code has been executed many times.
The HotSpot JVM will try to identify "hot spots" in your code. Hot spots are pieces of your code that are executed many many times. To do this, the JVM will "count" the executions of various instructions, and when it determines a certain piece is executed frequently, it will trigger the JIT. (this is an approximation, but it's easy to understand explained this way).
The JIT (Just-In-Time) takes that piece of code, and tries to make it faster.
The techniques used by the JIT to make your code run faster are a lot, but the one that most commonly creates confusion are :
So, the proper answer to your question is that an empty loop, after being JITed, takes no time to execute .. most probably is not there anymore.
Again, there are many other optimizations, but in my experience these are among those that have created most headaches.
Moreover, JIT is being improved in any new version of Java, and sometimes it is even a bit different depending on the platform (since it is to some extent platform specific). Optimizations done by the JIT are difficult to understand, because you cannot usually find them using javap and inspecting bytecode, even if in recent versions of Java some of these optimizations have been moved to the compiler directly (for example, since Java 6 the compiler is able to detect and warn about unused local variables and private methods).
If you are writing some loops to test something, it is usually good practice to have the loop inside a method, call the method a few times BEFORE timing it, to give it a "speed up" round, and then perform the timed loop.
This usually triggers the JIT in a simple program like yours, even if there is no guarantee that it will actually trigger (or that it even exists on a certain platform).
If you want to get paranoid about JIT or non JIT timing (I did): make a first round, timing each execution of the loop, and wait until the timing stabilize (for example, difference from the average less than 10%), then start with your "real" timing.
JIT 不会启动代码块,直到它确定这样做有一些好处。这意味着某些代码的前几次传递不会被 JIT 处理。
The JIT doesn't kick in on a chunk of code until it determines that there is some benefit to doing so. That means the first few passes through some code won't be JITed.