看看下面的代码:
class Test
{
public static void main(String abc[])
{
for( int N=1; N <= 1_000_000_000; N=N*10)
{
long t1 = System.nanoTime();
start(N);
long t2 = System.nanoTime() - t1;
System.out.println("Time taken for " + N + " : " + t2);
}
}
public static void start( int N )
{
int j=1;
for(int i=0; i<=N; i++)
j=j*i;
}
}
上述问题产生的输出是:
Time taken for 1 : 7267
Time taken for 10 : 3312
Time taken for 100 : 7908
Time taken for 1000 : 51181
Time taken for 10000 : 432124
Time taken for 100000 : 4313696
Time taken for 1000000 : 9347132
Time taken for 10000000 : 858
Time taken for 100000000 : 658
Time taken for 1000000000 : 750
问题:
1.) 为什么 N=1 所花费的时间异常大于 N=10 所花费的时间? (有时甚至超过N=100)
2.) 为什么 N=10M 及以后花费的时间异常短?
上述问题中指出的模式意义深远,甚至在多次迭代后仍然存在。 与memoization有什么关系吗?在这里?
编辑:
感谢您的回答。我想用实际的循环替换方法调用。但是现在,没有JIT优化。为什么不 ?将语句放在有助于优化过程的方法中吗? 修改后的代码如下:
class test
{
public static void main(String abc[])
{
for( int k=1; k<=3; k++)
{
for( int N=1; N<=1_000_000_000; N=N*10)
{
long t1 = System.nanoTime();
int j=1;
for(int i=0; i<=N; i++)
j=j*i;
long t2 = System.nanoTime() - t1;
System.out.println("Time taken for "+ N + " : "+ t2);
}
}
}
}
编辑 2: 以上修改后的代码输出:
Time taken for 1 : 2160
Time taken for 10 : 1142
Time taken for 100 : 2651
Time taken for 1000 : 19453
Time taken for 10000 : 407754
Time taken for 100000 : 4648124
Time taken for 1000000 : 12859417
Time taken for 10000000 : 13706643
Time taken for 100000000 : 136928177
Time taken for 1000000000 : 1368847843
Time taken for 1 : 264
Time taken for 10 : 233
Time taken for 100 : 332
Time taken for 1000 : 1562
Time taken for 10000 : 17341
Time taken for 100000 : 136869
Time taken for 1000000 : 1366934
Time taken for 10000000 : 13689017
Time taken for 100000000 : 136887869
Time taken for 1000000000 : 1368178175
Time taken for 1 : 231
Time taken for 10 : 242
Time taken for 100 : 328
Time taken for 1000 : 1551
Time taken for 10000 : 13854
Time taken for 100000 : 136850
Time taken for 1000000 : 1366919
Time taken for 10000000 : 13692465
Time taken for 100000000 : 136833634
Time taken for 1000000000 : 1368862705
最佳答案
1.) Why is time taken for N=1 unusually greater than the N=10
因为这是 VM 第一次看到该代码 - 它可能决定只解释它,或者将它 JIT 为 native 代码需要一点时间,但可能没有优化。这是对 Java 进行基准测试的“陷阱”之一。
2.) Why is time taken for N=10M and onwards unusually lower ?
那时,JIT 更加努力地优化代码 - 将其减少到几乎没有。
特别是,如果您多次运行此代码(只是在一个循环中),您将看到 JIT 编译器优化的效果:
Time taken for 1 : 3732
Time taken for 10 : 1399
Time taken for 100 : 3266
Time taken for 1000 : 26591
Time taken for 10000 : 278508
Time taken for 100000 : 2496773
Time taken for 1000000 : 4745361
Time taken for 10000000 : 933
Time taken for 100000000 : 466
Time taken for 1000000000 : 933
Time taken for 1 : 933
Time taken for 10 : 467
Time taken for 100 : 466
Time taken for 1000 : 466
Time taken for 10000 : 933
Time taken for 100000 : 466
Time taken for 1000000 : 933
Time taken for 10000000 : 467
Time taken for 100000000 : 467
Time taken for 1000000000 : 466
Time taken for 1 : 467
Time taken for 10 : 467
Time taken for 100 : 466
Time taken for 1000 : 466
Time taken for 10000 : 466
Time taken for 100000 : 467
Time taken for 1000000 : 466
Time taken for 10000000 : 466
Time taken for 100000000 : 466
Time taken for 1000000000 : 466
如您所见,在第一个循环之后,无论输入如何(模块噪声 - 基本上总是 ~460ns 或 ~933ns,不可预测),循环都花费相同的时间,这意味着 JIT 已经优化了循环。
如果你实际返回了j
,和将i
的初始值改为1
而不是0
,您将看到您期望的那种结果。将 i
的初始值更改为 1
是因为否则 JIT 会发现您最终将始终返回 0。
关于Java乘法奇怪的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17761515/