2012-03-06 56 views
2

计算机具有RAM内存,但它也具有更小,更快的CPU内存缓存。 Java内存模型保证在访问变量volatile时刷新CPU内存缓存,但由于我们只在单个线程的单个类中使用该变量变量,因此JIT不会仅仅优化它。在Java中,如何刷新CPU内存缓存以便从RAM内存中检索最新内容?

要(在某一点时,我们调用了Thread.sleep(只表现)足够长的时间)诊断的错误,我们需要能够做这样的事情(而不是睡眠()):

System.clearCpuCache(); 

什么是最简单和最可靠的方法来实现这样的方法?它应该保证它不会JIT优化掉缓存刷新。 我们只能在启用JIT的情况下重现我们的错误,因此禁用JIT不是一种选择。

+1

进入和退出'synchronized'块也应努力 – 2012-03-06 11:20:32

+1

我从来没有听说过的JIT优化远离易失性写入。你有任何文件证明它会这么做吗? – Johannes 2012-03-06 11:39:20

+0

@Johannes完全没有证据,只是怀疑:) – 2012-03-06 13:31:22

回答

8

你一般不能。除性能外,缓存的存在对应用程序是透明的。这也适用于多处理器系统,只要缓存系统是“高速缓存一致性”,这几乎是当今所有使用的平台。

因此,你的错误在别处。

像易失性和同步块这样的事情本身不影响缓存一致性,而是注册优化,使用原子指令(包括冲洗存储缓冲区,这与缓存不一样!),等等。这些是你应该看的东西(当然,鉴于你的描述中缺乏细节,很难说,但作为第一个猜测),而不是尝试刷新缓存。

+0

在这种情况下,如何刷新存储缓冲区可靠? – 2012-03-06 13:34:40

+1

@GeoffreyDeSmet:取决于。在x86上,例如“mfence”指令。在Java中,使用volatile,synchronized块等会导致JVM根据需要发布这些指令。 – janneb 2012-03-06 14:04:53

1

访问volatile变量应该绕过缓存,而不是刷新它。所以清除缓存不应该影响volatile的行为。 错误是如何体现的?在Thread.sleep()之后和同一个线程中看到过时的值吗? 多年前我为Java兼容性测试套件编写了测试。其中一项测试证明,volatile变量可以从缓存中读取,而不是从主内存中读取。我想知道这个bug是否仍然存在。请寄给我详细资料给rfq(at)list.ru,我会尝试创建令人信服的测试。

1

我不确定这是否是这种情况(需要更多详细信息!),但有一点需要注意的是,如果您发现围绕易失性的硬线程错误,则易失性不一定是原子性的。

即你可能认为你已经更新了一个易变的变量,并且新的值应该是可见的,但实际上你并不是因为完整的更新没有完成。

http://www.ibm.com/developerworks/java/library/j-jtp11234/

1

您是否尝试过与AtomicInteger

我看不到如何从cpu高速缓存中获取volatile int的错误版本,如果该值始终由同一个线程更改/读取。也许尝试打印出哪个线程是活跃在每个读/写的变量,只是要100%地肯定:

System.out.println(Thread.currentThread().getName());