我有一个我不知道的Java性能问题';我不明白
我写了一些代码来创建多维数组,而不是数组数组,这样可以节省一些内存。然后我运行了一些测试,将它的速度与常规Java数组(int[][])的速度进行比较,因为我不希望我的程序运行得更慢,即使它节省了一些内存。我在计时测试中看到的让我困惑。以下是测试运行的典型结果。时间是针对相同的代码位。注意后两个比前四个大得多 时间:58343722纳秒我有一个我不知道的Java性能问题';我不明白,java,performance,Java,Performance,我写了一些代码来创建多维数组,而不是数组数组,这样可以节省一些内存。然后我运行了一些测试,将它的速度与常规Java数组(int[][])的速度进行比较,因为我不希望我的程序运行得更慢,即使它节省了一些内存。我在计时测试中看到的让我困惑。以下是测试运行的典型结果。时间是针对相同的代码位。注意后两个比前四个大得多 时间:58343722纳秒 时间:59451156纳秒 时间:51374777纳秒 时间:61777424纳秒 时间:813156695纳秒 时间:782140511纳秒 现在我想到的第一
时间:59451156纳秒
时间:51374777纳秒 时间:61777424纳秒
时间:813156695纳秒
时间:782140511纳秒 现在我想到的第一件事是垃圾回收员在干什么。我将内存限制提高到5GB(-Xmx5g),这样垃圾收集器就不会启动。没有什么变化。我把东西搬来搬去,但图案保持不变 那么模式是什么呢?在前三次中,代码位在函数中,我调用它三次。在第二个三次中,代码位在单个函数中重复三次。因此,模式是,每当代码位在同一个函数中多次运行时,运行代码位所需的时间将从第二个代码位开始迅速上升,然后继续上升 我确实发现了一个会产生如下结果的变更: 时间:58729424纳秒
时间:59965426纳秒
时间:51441618纳秒 时间:57359741纳秒
时间:65362705纳秒
时间:857942387纳秒 我所做的是在第二个3的代码位之间添加一毫秒的延迟。这样做只会加快块中第二个代码位的速度,之后的任何代码位都不会因为延迟而加速 坦白说,我很困惑。我无法解释这种行为。有人能解释一下发生了什么事吗 代码如下:
package multidimensionalarraytests;
import java.lang.reflect.Array;
import java.util.logging.Level;
import java.util.logging.Logger;
public class MultidimensionalArrayTests {
static ArrayInt2Dv1 array=new ArrayInt2Dv1(10000,10000);
public static void main(String[] args) {
System.out.println("ignore the warmup");
test();
test();
combined();
combined();
System.out.println("running tests");
test();
test();
test();
System.out.println();
combined();
}
static long test(){
int value=1;
long start,stop,time;
System.out.print("time: ");
start=System.nanoTime();
for(int x=0;x<array.length1;x++){
for(int y=0;y<array.length2;y++){
array.set(x, y, value);
value=array.get(x, y);
}
}
stop=System.nanoTime();
time=(stop-start);
System.out.println(time+" ns");
return time;
}
static void combined(){
int value=1;
long start,stop,time;
System.out.print("time: ");
start=System.nanoTime();
for(int x=0;x<array.length1;x++){
for(int y=0;y<array.length2;y++){
array.set(x, y, value);
value=array.get(x, y);
}
}
stop=System.nanoTime();
time=(stop-start);
System.out.println(time+" ns");
//try {Thread.sleep(1);} catch (InterruptedException ex) {}
System.out.print("time: ");
start=System.nanoTime();
for(int x=0;x<array.length1;x++){
for(int y=0;y<array.length2;y++){
array.set(x, y, value);
value=array.get(x, y);
}
}
stop=System.nanoTime();
time=(stop-start);
System.out.println(time+" ns");
//try {Thread.sleep(60000);} catch (InterruptedException ex) {}
System.out.print("time: ");
start=System.nanoTime();
for(int x=0;x<array.length1;x++){
for(int y=0;y<array.length2;y++){
array.set(x, y, value);
value=array.get(x, y);
}
}
stop=System.nanoTime();
time=(stop-start);
System.out.println(time+" ns");
}
}
---编辑---
Windows7上的输出选项为-Xms5g-Xmx5g-XX:+PrintCompilation-verbose:gc-XX:CICompilerCount=1-Xbatch
time: 299 1 b multidimensionalarraytests.ArrayInt2Dv1::set (15 bytes)
302 2 b multidimensionalarraytests.ArrayInt2Dv1::get (14 bytes)
303 1 % b multidimensionalarraytests.MultidimensionalArrayTests::test @ 31 (114 bytes)
358 1 % multidimensionalarraytests.MultidimensionalArrayTests::test @ -2 (114 bytes) made not entrant
60671451 ns
359 3 b multidimensionalarraytests.MultidimensionalArrayTests::test (114 bytes)
time: 365 2 % b multidimensionalarraytests.MultidimensionalArrayTests::test @ 31 (114 bytes)
58104484 ns
time: 425 3 % b multidimensionalarraytests.MultidimensionalArrayTests::combined @ 31 (330 bytes)
69008251 ns
time: 806898159 ns
time: 845447596 ns
2146 4 b multidimensionalarraytests.MultidimensionalArrayTests::combined (330 bytes)
time: 52493169 ns
time: 804304528 ns
time: 845500191 ns
running tests
time: 51290771 ns
time: 51922285 ns
time: 51264108 ns
time: 52258679 ns
time: 842229025 ns
time: 871403625 ns
在Linux(同一台机器上VirtualBox上的Ubuntu)上使用相同的选项:
283 1 b java.lang.String::hashCode (60 bytes)
285 2 b sun.nio.cs.UTF_8$Encoder::encodeArrayLoop (490 bytes)
287 3 b java.lang.String::charAt (33 bytes)
287 4 b java.lang.String::indexOf (151 bytes)
297 5 b java.io.UnixFileSystem::normalize (75 bytes)
2850 6 b java.lang.String::lastIndexOf (156 bytes)
ignore the warmup
time: 5885 7 b multidimensionalarraytests.ArrayInt2Dv1::set (15 bytes)
5948 8 b multidimensionalarraytests.ArrayInt2Dv1::get (14 bytes)
5949 1% b multidimensionalarraytests.MultidimensionalArrayTests::test @ 31 (114 bytes)
11529998483 ns
17565 9 b multidimensionalarraytests.MultidimensionalArrayTests::test (114 bytes)
time: 1619622928 ns
time: 19718 2% b multidimensionalarraytests.MultidimensionalArrayTests::combined @ 31 (330 bytes)
475786382 ns
time: 288586857 ns
time: 315560700 ns
20789 10 b multidimensionalarraytests.MultidimensionalArrayTests::combined (330 bytes)
time: 460577230 ns
time: 311525066 ns
time: 312343429 ns
running tests
time: 310261854 ns
time: 298826592 ns
time: 304689920 ns
time: 315416579 ns
time: 299473245 ns
time: 290211350 ns
尝试
-XX:+printcomployment
这应该表明,在第一个循环迭代10000次之后,整个方法得到了优化。问题在于,第二/第三个循环在没有统计/计数器信息的情况下进行了优化。有时这并不重要,有时后面的循环会慢得多,如果交换循环的顺序,后面的循环会改进,第一个循环会变慢
解决这个问题的简单方法是将每个循环放在自己的方法中,每个循环都会得到适当的优化。对于初学者,请看一看好的建议。我修改了上面的代码以反映建议,并使用以下选项运行程序:-Xms5g-Xmx5g-XX:+printcomilation-verbose:gc-XX:CICompilerCount=1-Xbatch。不过,这并没有显著改变结果。我已经尝试过(使用更新的代码),但我无法在64位Ubuntu上使用Java6U26重现这种效果。在这里,所有六个运行时间彼此相差不超过10%(由于实时编译器的启动,预热时间确实会波动)。无法在使用Java 1.7.0-ea-b223(64位服务器vm 21.0-b17)的MacOS 10.6.8上重现。作为本/aix评论的后续内容,您是否可以提供您的设置(OS+java版本)以及是否使用其他选项运行该程序?我使用的是Windows 7,使用的是java 1.6.21和1.7.0,两者的结果相同。我只使用了上面列出的选项。好的,我明白你在说什么了。在combined()函数中,编译操作发生在第一组循环期间,而不是在其他循环期间。如果我添加ms sleeps,那么编译操作会在前两组循环中发生,但不会在第三组循环中发生。编译操作发生的循环对应于更快的执行。我觉得很奇怪,它只会优化第一组循环,而不会优化其他循环。嗯,我至少知道它在做什么,但不知道为什么。但奇怪的是,当我使用int[]]而不是我的ArrayInt2Dv1时,会进行相同的优化,但是没有在最后两个循环上运行优化不会造成时间损失。这很烦人,因为如果不记住优化器的工作原理,我就不能简单地用多维数组替换Java数组,否则事情可能会变得相当缓慢。所有循环都经过优化,但是后面的循环都是基于没有动态收集的信息进行优化的(由于该方法是根据当时的信息立即编译的)
283 1 b java.lang.String::hashCode (60 bytes)
285 2 b sun.nio.cs.UTF_8$Encoder::encodeArrayLoop (490 bytes)
287 3 b java.lang.String::charAt (33 bytes)
287 4 b java.lang.String::indexOf (151 bytes)
297 5 b java.io.UnixFileSystem::normalize (75 bytes)
2850 6 b java.lang.String::lastIndexOf (156 bytes)
ignore the warmup
time: 5885 7 b multidimensionalarraytests.ArrayInt2Dv1::set (15 bytes)
5948 8 b multidimensionalarraytests.ArrayInt2Dv1::get (14 bytes)
5949 1% b multidimensionalarraytests.MultidimensionalArrayTests::test @ 31 (114 bytes)
11529998483 ns
17565 9 b multidimensionalarraytests.MultidimensionalArrayTests::test (114 bytes)
time: 1619622928 ns
time: 19718 2% b multidimensionalarraytests.MultidimensionalArrayTests::combined @ 31 (330 bytes)
475786382 ns
time: 288586857 ns
time: 315560700 ns
20789 10 b multidimensionalarraytests.MultidimensionalArrayTests::combined (330 bytes)
time: 460577230 ns
time: 311525066 ns
time: 312343429 ns
running tests
time: 310261854 ns
time: 298826592 ns
time: 304689920 ns
time: 315416579 ns
time: 299473245 ns
time: 290211350 ns