我的java数组代码表现得很有趣

时间:2014-07-23 01:52:24

标签: java algorithm sorting optimization compiler-optimization

我正在研究算法,我一直在成功优化它,直到我遇到这个奇怪的问题:

将数组C作为参数传递给方法。

       int lim = C.length; 
      double A[]=new double[lim];
      double B[]=new double[lim];
      for (int I = offset; I < lim; I++) {
      A[ (int) B[C[I]] ] = C[I];
      }

ABdouble数组,C是整数数组。它们都是相同的尺寸 我注意到,当我使用System.nanoTime()找到时间差异时,此代码的运行速度要慢得多。

通过问题排查,我发现如果我将C[I]替换为I或使用代码中嵌入的值初始化的常量或任何变量,它的运行速度比其值即将到来的速度快很多倍来自代码中未预定义的源。

作为最终测试,我用随机整数替换C[I]并获得相同的慢速。怎么了? JVM是否针对预定义变量优化代码?如果不在代码中定义数组的内容(我肯定会解决这个问题),我可以合理地解决这个问题吗?

如果我可以解决这个问题,优化将产生一种新的排序算法,其运行速度比Java 7的 QuickSort算法的实现快得多。它已经比n&lt; 8000左右,用于多种输入。

目前,我已经录制了它(在我的机器上),在3.8-3.9秒内排序了800万个数字(类型为double),而Java的QuickSort implementation(Arrays.sort())在同一台机器上执行了大约1.53秒。我已经跟踪了2个for循环中这行代码的减速到2次,我需要帮助。

1 个答案:

答案 0 :(得分:3)

我怀疑减速是由内存位置问题引起的。

当你有非常大的数组时,它们将跨越多个(虚拟内存)页面。因此,如果您尝试以非顺序方式访问数组元素,您最终可能会以某种方式访问​​内存,从而抵消硬件用于快速显示内存访问的“智能”的影响:

  • 如果您访问许多不同的位置,它们就不再适合缓存了。这会导致缓存未命中,并且CPU必须从物理内存中取出,这会减慢速度。

  • 访问的非顺序性质意味着广泛的内存提取无助于提高性能。

  • 当位置分散在大量页面上时,您可能会错过TLB(转换后备缓冲区)硬件...这会缓存vm页面条目。 TLB未命中通常会导致更多内存访问,以从内存中读取页表条目。


很难说这是否真的导致算法速度变慢。 (虽然我认为你的实验结果支持这个命题......)

如果这是潜在的问题,那么你无能为力。它是现代计算机工作方式所固有的。如果您的算法需要通过足够大的阵列进行“随机”访问,则性能将受到物理内存速度的限制。