Joshua Bloch 在推特上发了一个链接( http://igoro.com/archive/gallery-of-processor-cache-effects/ ),使用高级编程语言(如C#)演示了CPU缓存的效果。强烈推荐!
那我们能否在Java中演示同样的效果呢?乍一看,这种可能性对我们不利:Java不是编译成本机代码,而是编译成中间字节码,而中间字节码可能会编译成本机代码,也可能不会编译成本机代码(取决于具体情况,例如JIT)。那么,我们能在Java程序中显示缓存效果吗?
是的,可以!
当心局部优化
在继续之前,我想提醒大家关于局部优化的问题。这篇文章向你展示了如何在一个非常初级的层次上优化你的程序。这很有趣,也很有启发性,但大多数情况下,将知识应用到实际应用中是浪费时间。首先,现实世界中的应用程序通常可以通过全局优化得到更好的优化。大多数情况下,你可以用更好的算法来代替算法。其次,局部优化是一种可以由编译器自动完成的优化。让他们去做吧。
然而,本文让您更好地了解Java是如何在处理器上运行的。
一个简单的问题
Igor Ostrovsky以一个简单的问题开始他的文章:以下哪种方法运行得更快?
public class CacheLines { private static int[] array = new int[64 * 1024 * 10]; private static void loop1() { int length = array.length; for (int i = 0; i < length; i=i+1) array[i] --; } private static void loop2() { int length = array.length; for (int i = 0; i < length; i += 2) array[i] --; } }
令我惊讶的是,第一种方法是快速的。它的工作量是原来的两倍,但速度更快。
我还用更大的增量步骤实现了这个方法,一直到loop128,它的增量是128。以下是我的台式电脑的结果:
Step 1/10000 took 1250.627 ms that's 100% of the expected time Step 2/10000 took 1668.458 ms that's 266% of the expected time Step 4/10000 took 1159.842 ms that's 370% of the expected time Step 8/10000 took 1039.095 ms that's 664% of the expected time Step 16/10000 took 1022.674 ms that's 1308% of the expected time Step 32/10000 took 530.95 ms that's 1358% of the expected time Step 64/10000 took 272.518 ms that's 1394% of the expected time Step 128/10000 took 138.968 ms that's 1422% of the expected time Step 256/10000 took 100.921 ms that's 2065% of the expected time
在第16步之前,程序的运行速度或多或少与第1步版本相同。这就是缓存线的效果。我建议读一下原文的解释( http://igoro.com/archive/gallery-of-processor-cache-