最近我注意到声明一个包含64个元素的数组比用65个元素声明相同类型的数组快得多(> 1000倍).
这是我用来测试这个的代码:
public class Tests{
public static void main(String args[]){
double start = System.nanoTime();
int job = 100000000;//100 million
for(int i = 0; i < job; i++){
double[] test = new double[64];
}
double end = System.nanoTime();
System.out.println("Total runtime = " + (end-start)/1000000 + " ms");
}
}
Run Code Online (Sandbox Code Playgroud)
这将运行在大约6毫秒,如果我更换new double[64]用new double[65]它需要大约7秒.如果作业分布在越来越多的线程中,这个问题会变得更加严重,这是我的问题所在.
不同类型的数组(例如int[65]或)也会出现此问题String[65].大字符串不会发生此问题:String test = "many characters";但是在更改为此字符串时会发生此问题String test = i + "";
我想知道为什么会这样,如果有可能绕过这个问题.
nos*_*sid 88
您正在观察由Java VM的JIT编译器执行的优化所导致的行为.此行为可通过最多64个元素的标量数组触发,并且不会被大于64的数组触发.
在详细介绍之前,让我们仔细看看循环体:
double[] test = new double[64];
Run Code Online (Sandbox Code Playgroud)
身体没有效果(可观察到的行为).这意味着无论是否执行此语句,它在程序执行之外都没有区别.整个循环也是如此.因此可能会发生,代码优化器将循环转换为具有相同功能和不同时序行为的某些(或没有).
对于基准测试,您至少应遵循以下两个准则.如果你这样做了,差异就会明显变小.
现在让我们详细介绍一下.毫不奇怪,对于不超过64个元素的标量数组,会触发优化.优化是Escape分析的一部分.它将小对象和小数组放入堆栈而不是在堆上分配它们 - 甚至更好地完全优化它们.您可以在2005年撰写的Brian Goetz的以下文章中找到有关它的一些信息:
可以使用命令行选项禁用优化-XX:-DoEscapeAnalysis.标量数组的魔术值64也可以在命令行中更改.如果按如下方式执行程序,则具有64和65个元素的数组之间没有区别:
java -XX:EliminateAllocationArraySizeLimit=65 Tests
Run Code Online (Sandbox Code Playgroud)
话虽如此,我强烈反对使用这样的命令行选项.我怀疑它在现实应用中有很大的不同.我只会使用它,如果我绝对相信必要性 - 而不是基于某些伪基准测试的结果.