Java 内存模型和局部变量

Java memory model and local variable

此问题与java内存模型有关。

我有一个java方法:

public class DataUtil{
  public void process(){
    int c=0;
    c=c+1;

    System.out.println(c);
  }
}

在“System.out.println(c)”这一行中,println 方法在哪里获取c 变量的值并将其打印到屏幕上? CPU 缓存或 RAM

Java 内存模型对此没有规定 - 它专注于多线程程序的行为。
局部变量分配在 堆栈 上。函数的参数,例如 println,也通过堆栈传递 - 它们在调用之前被压入堆栈顶部(根据 调用约定 )。这就是字节码中发生的事情,尽管 JIT 编译器或解释器也可能使用 CPU 寄存器,并且不使用 RAM 中的堆栈。

明确地说,这个问题和这个答案只是关于一个线程的程序的行为。我下面说的很多东西可能不适用于多线程程序。

Where does the println method takes the value of c variable and prints it on screen? CPU cache, or RAM

Java 内存模型 (JLS 17.4) 没有说什么 明确关于高速缓存和 RAM。通常,它指定可见性行为而不规定特定编译器实现该行为的方式。 JMM 要求在线程写入变量并随后读取变量时存在 happens before 关系。 happens before 约束生成的代码以某种方式运行。但是,它不强制要求任何特定的实现方法来实现这些限制。

在您的示例中,JMM 甚至没有对值是来自缓存还是 RAM 设置隐式约束。 c 变量只能由一个线程访问。 (这是一个局部变量!)。所以编译器可以(理论上)将变量的值存储在任何地方1。唯一的限制是访问变量时使用最新的值。编译器只需要跟踪最新变量的保存位置 ...

作为一般规则,JMM 只对 不同 线程共享的变量和对象有一些有趣的说法。


1 - 在寄存器中,在 RAM 中,在高速缓存中,在硬件堆栈中......甚至写在一张纸上,如果你的硬件平台支持那.


如果您在更广泛的意义上使用“内存模型”,那么简单的答案是“我们不能说”。

  • 在根据主内存和高速缓存指定内存模型的语言(不是 Java!)中,内存模型很可能 不限制这个例子。

  • 如果你不是在谈论任何特定的内存模型,而只是询问值是从缓存还是 RAM 中获取的,那么我们不能说......因为这是一个 语言实现的实现细节。例如JVM。

我们可以说高度确定2是该实现将获取并打印[的最新值=11=] 来自 某个地方 在这个例子中。

在 Java 的情况下,JLS 表示它 必须 return 最新值。 (如果您想查看,它在 JLS 17.4 中。)JLS 将其留给 Java 实现来决定如何执行此操作。

可以肯定地说,任何 JVM 实现都会提出可靠的解决方案;即,将使用变量的最新值。但是弄清楚细节将是一项艰巨的任务……而且(IMO)不值得付出努力。 (您不需要了解沃尔沃 264 自动变速箱的内部构造即可驾驶汽车。)


2 - 我们可以肯定,因为没有大量的单线程应用程序因读写变量问题而无法工作的错误报告。另外,如果有任何疑问,可以检查 JIT 编译器源代码以了解它的作用,或者分析它生成的本机代码。