将本地内存刷新到全局内存意味着什么?

Jac*_*ith 10 java memory multithreading model

我知道Java中volatile变量的目的是对其他线程立即可以看到对这些变量的写入.我也知道同步块的一个影响是将线程本地内存刷新到全局内存.

在这种情况下,我从未完全理解对"线程本地"内存的引用.我理解只存在于堆栈上的数据是线程本地的,但是当谈论堆上的对象时,我的理解变得模糊.

我希望能得到以下几点的评论:

  1. 在具有多个处理器的计算机上执行时,是否刷新线程本地内存只是将CPU缓存刷新到RAM中?

  2. 在单处理器机器上执行时,这是否意味着什么?

  3. 如果堆可能在两个不同的内存位置(每个由不同的线程访问)具有相同的变量,那么在什么情况下会出现这种情况?这对垃圾收集有什么影响?虚拟机如何积极地做这种事情?

  4. (编辑:添加问题4)退出同步块时刷新了什么数据?它是本地线程的一切吗?它只是在同步块内写的吗?

    Object x = goGetXFromHeap(); // x.f is 1 here    
    Object y = goGetYFromHeap(); // y.f is 11 here
    Object z = goGetZFromHead(); // z.f is 111 here
    
    y.f = 12;
    
    synchronized(x)
    {
        x.f = 2;
        z.f = 112;
    }
    
    // will only x be flushed on exit of the block? 
    // will the update to y get flushed?
    // will the update to z get flushed?
    
    Run Code Online (Sandbox Code Playgroud)

总的来说,我想要了解线程局部是否意味着只有一个CPU可以物理访问的内存,或者VM是否存在逻辑线程局部堆分区?

任何演示文稿或文档的链接都会非常有用.我花时间研究这个,虽然我找到了很多不错的文献,但我还是无法满足我对线程局部记忆的不同情况和定义的好奇心.

非常感谢.

Tho*_*nin 6

你所谈论的同花顺被称为"记忆障碍".这意味着CPU确保从RAM中看到的内容也可以从其他CPU /内核中查看.它意味着两件事:

  • JIT编译器刷新CPU寄存器.通常,代码可以保留CPU寄存器中的一些全局可见数据(例如,实例字段内容)的副本.从其他线程看不到寄存器.因此,一半的工作synchronized是确保不维护这样的缓存.

  • synchronized实现还执行内存屏障,以确保从当前内核对RAM的所有更改都传播到主RAM(或者至少所有其他内核都知道此内核具有最新值 - 缓存一致性协议可能相当复杂).

第二项工作在单处理器系统上是微不足道的(我的意思是,具有单核CPU的系统具有单核)但是单处理器系统现在往往变得更加罕见.

至于线程局部堆,理论上可以做到这一点,但通常不值得努力,因为没有什么可以告诉内存的哪些部分需要刷新synchronized.这是带共享内存的线程模型的限制:应该共享所有内存.在第一次遇到时synchronized,JVM应该将其所有"线程局部堆对象"刷新到主RAM.

然而,Sun最近的JVM可以执行"逃逸分析",其中JVM成功地证明某些实例永远不会从其他线程中看到.例如,这是典型的StringBuilderjavac处理字符串连接而创建的实例.如果实例永远不作为参数传递给其他方法,那么它不会变为"全局可见".这使得它有资格进行线程局部堆分配,或者甚至在适当的情况下,用于基于堆栈的分配.请注意,在这种情况下,没有重复; 实例不在"两个地方同时".只有JVM才能将实例保存在私有的地方,而不会产生内存障碍.