为什么共享变量缓存在CPU缓存中?

问题描述 投票:0回答:1

我正在尝试理解Java内存模型,但未能对CPU缓存有所了解。

据我所知,在JVM中,我们有以下位置来存储本地和共享变量:

local variables -- on thread stack

shared variables -- in memory, but every CPU cache has a copy of it

所以我的问题是:为什么在堆栈中存储局部变量,并在CPU缓存中(缓存)共享变量?为什么不相反(假设CPU缓存太昂贵而无法存储),我们在CPU缓存中缓存局部变量并只从内存中获取共享变量?这是Java语言设计还是计算机体系结构的一部分?

另外:就像“CPU缓存”一样简单,如果几个CPU共享一个缓存怎么办?在具有多级缓存的系统中,哪个级别的缓存将共享变量的副本存储在?此外,如果在同一CPU核心中运行多于1个线程,这是否意味着它们共享同一组缓存的共享变量,因此即使共享变量未定义volatile,变量的访问仍然是立即的在同一个CPU上运行的其他线程可见吗?

java multithreading visibility shared-variable
1个回答
1
投票

在本地代码的上下文之外,“本地”和“共享”变量毫无意义。它们不会影响状态缓存的位置,甚至也不会影响缓存状态。根据你的国家存储地点来思考或推理它甚至都没有用; JMM存在的全部原因是这样的细节(从架构到架构不同)不会暴露给程序员。依靠低级硬件细节,您会询问有关JMM的错误问题。它对你的应用程序没有用,它使它变得脆弱,更容易破解,更难以推理,并且不太便携。

也就是说,一般来说,您应该假设任何程序状态(如果不是所有状态)都有资格被缓存。事实上,缓存的内容实际上并不重要,只是任何东西都可以,无论是原始类型还是引用类型,甚至是由多个字段封装的状态变量。无论线程运行的指令是什么(这些指令也因架构而异 - 请注意!),这些指令默认返回CPU以确定与缓存相关的内容和不缓存的内容;程序员不可能自己这样做(虽然可以影响缓存状态变量的位置,看看false sharing是什么)。

同样,我们还可以对x86做一些更多的概括,有效的原始类型可能放在寄存器上,因为P / ALU能够以最快的速度使用它们。还有别的事。如果它们是核心本地的原语可以被移动到L1 / 2缓存,它们肯定可能很快被覆盖。如果CPU认为将来会有上下文切换,或者它不能,则可能会将状态变量放在共享L3上。硬件专家需要对此作出回应。

理想情况下,状态变量将存储在最近的高速缓存(寄存器,L1 / 2/3,然后是主存储器)中,并存储在处理器单元中。这是由CPU决定的。在Java级别上无法推断缓存语义。即使启用了超线程(我不确定AMD的等价物是什么),也不允许线程共享资源,即便如此,如果是这样的话,请回想一下,可见性不是与共享状态变量相关的唯一问题;在处理器执行流水线操作的情况下,您仍然需要相应的指令来确保正确的排序(即使您在CPU上摆脱了读/写缓冲),无论是hwsync还是相应的栅栏或其他。

同样,关于缓存属性的推理也没有用,因为JMM会为你处理这个问题,因为它是不确定的,在何时/何时/什么是缓存。此外,即使您确实知道何时/何时/有什么问题,您仍然无法推断数据可见性;所有缓存都以相同的方式处理缓存数据,您需要依赖处理器更新ME(O)SI状态,指令排序,加载/存储缓冲,回写/通过等之间的缓存状态。你还没有处理过操作系统和JVM级别可能出现的问题。同样,幸运的是,JDK允许您使用基本工具,如volatilefinal和原子,这些工具在所有平台上一致地工作,并生成可预测且易于理解的代码。

© www.soinside.com 2019 - 2024. All rights reserved.