在Java中,我可以决定我的字段存储在哪里吗:寄存器、缓存还是内存?

5

我知道这是自动完成的 - 访问频率越高的数据存储在离处理器更近的位置。但是我能否使用Java语法来影响它们的放置呢? 我的理解是,volatile会将数据放置在三级缓存或RAM中,因为它对所有线程都可见,这是正确的吗?


这个回答解决了你的问题吗?Java volatile关键字 - luk2302
“但是我能用Java语法来影响它们的位置吗?” - 不行。这不是你(作为程序员)可以做出的决定,特别是Java规范不知道这些概念。因此,某些编译器或运行时可能会以一种方式行事,而另一些运行时可能会有所不同。 - luk2302
决定变量放在哪里是JIT的工作,而不是开发人员的工作,因此您无法控制它。规范也从未说明易失性变量放置在L3缓存中,只是为其读/写行为提供了一些保证。 - haoyu wang
3个回答

6
不,Java语法不允许直接访问硬件。Java语言和虚拟机规范是管理Java代码如何解释的合同,它明确编写为针对一个虚拟机而非实际机器。
第1.2节可知:
引用:

Java虚拟机是Java平台的基石。它是技术的组成部分,负责实现其硬件和操作系统无关性、编译后的代码大小小以及保护用户免受恶意程序侵害。

Java虚拟机是一台抽象的计算机。它与真实的计算机类似,在运行时具有指令集并操作各种内存区域。使用虚拟机实现编程语言相当常见;最著名的虚拟机可能是UCSD Pascal的P-Code机器。

Java虚拟机甚至不需要可访问的寄存器或高速缓存。从规范的角度来看,图灵机完全可以实现符合Java虚拟机规范的要求。

1
没有明确的语言支持或JVM规范并不意味着在较低层面上发生的事情没有影响力。 - pveentjer
@pveentjer - 你可以合理猜测JVM实现会做什么,甚至可以查看特定版本的源代码;但是一般的约定是JVM实现可以选择做任何事情,只要它们遵守规范。 - tucuxi
这种行为你无法在“源代码”中查找。你需要了解硬件实际的工作原理。 - pveentjer
@pveentjer 这个 JVM的源代码 针对每种支持的架构进行了描述,准确地说明了要放置和何时出现。当然,编写此代码的人深刻理解硬件。我不认为代码很简单 - 但是您可以通过查看该代码,在足够的时间内找出为特定JVM和架构分配寄存器的方法。 - tucuxi
1
“寄存器”并不是很重要,因为它们只是体系结构级别的寄存器,并不能真正反映CPU内部的情况(处理器通过ROB将体系结构级别的寄存器重新命名并分配给物理寄存器)。确保缓存行处于适当状态,从而将对象加载到L1D中的所有内容都不属于ISA的范畴;这些都是微架构的一部分。这就是OP所问的内容。因此,仅仅盯着生成的汇编代码是不足以理解实际发生了什么的。 - pveentjer

1
Java在优化方面有很大的不同。作为开发人员,您可以在代码中说明需要执行的操作。然后,在运行时,即时编译器会查看正在进行的操作,然后(如果必要)将“慢”的Java字节码转换为高度优化的机器码。
换句话说:JIT会决定哪些代码值得优化。这可能包括优化的“数据布局”。
但是如上所述,您作为开发人员在此方面没有“发言权”。

0

这种行为是无法控制的。

如果 CPU 读取对象的字段,则该对象将被拉入 L1d,这与字段是否易失无关。

无论字段被访问一次还是多次,它都会最终进入 L1d。除非您有一个非暂态的载入/存储;但是此行为从 Java 中无法访问。

易失可以防止编译器和 CPU / 内存子系统级别上的指令重排序。在 X86 的情况下,由于 X86 的 TSO 内存模型,易失性读取是免费的(获取语义)。易失性写入通过停止前端执行负载直到存储缓冲区已被耗尽来实现。这样可以防止较旧的存储与不同地址的较新加载重新排序。

更多信息请参见: https://shipilev.net/blog/2014/on-the-fence-with-dependencies/


一旦即时优化器运行,如果检测到代码没有任何效果,则很可能会完全删除该代码 - 因此,在死代码消除后不会有L1d或任何其他分配。 - tucuxi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接