# Java内存结构

# 存储器的层次结构

timg

图来自 深入理解计算机系统 原书第三版 P421

L0 ~ L2 在CPU内部, L3 ~ L6 是CPU共享的.

其速度

image-20201110153414913

# 如何保证CPU数据的一致性

# 总线锁

当CPU去共享缓存中取数据时, 老的CPU会使用总线锁(L2和L3之间)把总线锁住, 防止产生数据的不一致性.

IMG_B919039ED2A0-1

# MESI协议

MESI 是一种缓存一致性协议, 新的CPU在保证数据一致性时使用的方式

缓存一致性协议有很多, Intel 使用的是 MESI 协议, 同时 Intel 的市场占有率又很高, 所以常说 MESI 协议.

详细信息: https://www.cnblogs.com/liushaodong/p/4777308.html

实现方式 CPU 每个 cache line标记四种状态(额外两位)

  • Modified 我改过
  • Exclusive 只有我在用
  • Shared 我读的时候别人也在读
  • Invalid 别人改过

MESI是缓存锁的实现方式之一, 有些无法被缓存的数据或者跨越多个缓存行的数据, 依然必须使用总线锁.

# 缓存行

CPU 读取缓存以cache line为基本单位,目前 64bytes

位于同一缓存行的两个不同数据,被两个不同CPU锁定,产生互相影响的伪共享问题

使用缓存行对齐能够提高效率

若 X 和 Y 在同一个缓存行中, CPU1 只用到 X, CPU2 只使用了 Y, CPU1修改了 X, 就会使 CPU2 重新 load 缓存行.

Java 可以通过 @Contended 注解来避免出现伪共享问题.

注意: 在运行的时候需要加入启动参数 -XX:-RestrictContended

# CPU乱序

乱序执行是CPU为了提高指令执行效率,会在一条指令执行过程中(比如去内存读数据(慢100倍)),去同时执行另一条指令,前提是两条指令没有依赖关系

合并写是指CPU写操作也可以进行合并, 详情可查看 扩展文章

合并写证明示例: JUC/029_WriteCombining

乱序执行的证明:JVM/jmm/Disorder.java

原始参考:https://preshing.com/20120515/memory-reordering-caught-in-the-act/

# CPU的内存屏障

Intel 的 CPU(x86) 上的内存屏障

  • sfence: 写(store)指令内存屏障, 在sfence指令前的写操作当必须在sfence指令后的写操作前完成。
  • lfence:读(load)指令内存屏障, 在lfence指令前的读操作当必须在lfence指令后的读操作前完成。
  • mfence:读写(modify/mix)混合指令内存屏障, 在mfence指令前的读写操作当必须在mfence指令后的读写操作前完成。

# 原子指令

原子指令,如x86上的”lock add/read/…” 指令是一个Full Barrier,执行时会锁住内存子系统来确保执行顺序,甚至跨多个CPU。Software Locks通常使用了内存屏障或原子指令来实现变量可见性和保持程序顺序

# JVM级别屏障规范

  • LoadLoad屏障:
    • 对于这样的语句Load1; LoadLoad; Load2,
    • 在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。
  • StoreStore屏障:
    • 对于这样的语句Store1; StoreStore; Store2,
    • 在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。
  • LoadStore屏障:
    • 对于这样的语句Load1; LoadStore; Store2,
    • 在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。
  • StoreLoad屏障:
    • 对于这样的语句Store1; StoreLoad; Load2,
    • 在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。

# volatile的实现细节

  1. 字节码层面 字节码层面只是加了一个 ACC_VOLATILE 识别码

  2. JVM 层面 volatile 内存区的读写 都加屏障

    StoreStoreBarrier

    volatile 写操作

    StoreLoadBarrier

    LoadLoadBarrier

    volatile 读操作

    LoadStoreBarrier

  3. OS 和硬件层面 使用工具 hsdis - HotSpot Dis Assembler , 可以观察 HotSpot 在虚拟机的汇编指令上的实现 windows lock 指令实现 | MESI实现

    内容扩展

# synchronized的实现细节

  1. 字节码层面 ACC_SYNCHRONIZED

    monitorenter(监视器开始)
    
    ...
    
    monitorexit (监视器结束)
    
    1
    2
    3
    4
    5
  2. JVM层面 C C++ 调用了操作系统提供的同步机制

  3. OS和硬件层面 X86 : lock cmpxchg / xxx 扩展内容

上次更新时间: 2020/11/12 上午1:35:10