JVM系列【4】内存模型

JVM系列笔记目录

  • 虚拟机的基础概念
  • class文件结构
  • class文件加载过程
  • jvm内存模型
  • JVM常用指令
  • GC与调优

硬件层数据一致性

- 存储器层次结构

JVM系列【4】内存模型_第1张图片

从L6-L0 空间由大变小,速度由慢到快。

-缓存一致性算法

CPU实现缓存一致性的协议很多,其中intel 使用的MESI(Modified Exclusive Shared Or Invalid)协议。具体可以参考:[MESI--CPU缓存一致性协议](https://www.cnblogs.com/z00377750/p/9180644.html)

JVM系列【4】内存模型_第2张图片

现代CPU的数据一致性实现=缓存锁(MESI...) +总线锁

-缓存行

缓存读取时的单位,一般是64Byte
使用缓存行的对齐能够提高效率

-伪共享

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

如何解决? 使用缓存行的对齐能够提高效率

CPU乱序问题

- 概念

CPU为了提高执行效率,会在一条指令执行的过程中(比如去内存取数据(慢100倍)),去同时执行另一条指令,前提是两条指令没有依赖关系。具体参考:[现代cpu的合并写技术对程序的影响](https://www.cnblogs.com/liushaodong/p/4777308.html)

-合并写

CPU上有一个WriteCombinBuffer,仅4个字节,比L1等级还高,某些写操作会合并在一起提交。[现代cpu的合并写技术对程序的影响](https://www.cnblogs.com/liushaodong/p/4777308.html)

-乱序证明

CPU乱序现象有大佬写程序模拟出来了,具体参考: Memory Reordering Caught in the Act

如何保证在特定情况下保证不乱序

硬件级别

X86 CPU级别内存屏障

sfence
store fence 在sfence指令前的写操作必须在sfence指令后的写操作前完成

lfence
load fence 在lfence指令前的读操作必须在lfence指令后的读操作前完成

mfence
mixed fence 在mfence指令前的读写操作必须在mfence指令后的读写操作前完成

CPU原子指令
如x86上的”lock …” 指令是一个Full Barrier,执行时会锁住内存子系统来确保执行顺序,甚至跨多个CPU

总结: Software Locks通常使用了内存屏障或原子指令来实现变量可见性和保持程序顺序

JVM级别

JSR113规范规定了4种内存屏障

LoadLoad屏障
对于语句Load1;LoadLoad;Load2,在Load2及后续读取指令要读取的数据被访问前,保证Load1要读取的数据被读取完毕

StoreStore屏障
对于语句Store1;StoreStore;Store2,在Store2及后续写操作执行前,保证Store1的写入操作对其它处理器可见

LoadStore屏障
对于语句Load1;StoreStore;Store2,在Store2及后续写操作被刷出前,保证Load1要读取的数据被读取完毕

StoreLoad屏障
对于语句Store1;StoreStore;Load2,在Load2及后续读取指令要执行前,保证Store1的写入操作对其它处理器可见

sychronized/volatile在字节码、JVM、硬件OS层面实现细节

- sychronized

  • 字节码层面

    sychronized m() : AccessFlag : ACC_VOLATILE

    sychronized(this){} : monitorenter monitorexit monitorenter

  • JVM层面

    C/C++ 调用操作系统的同步操作

  • 硬件OS层面

    X86 : lock cmpxchg / xxx

-volatile

  • 字节码层面
    AccessFlag : ACC_VOLATILE

  • JVM层面

    volatile内存区域都加屏障

    StoreStoreBarrier volatile 写操作 StoreLoadBarrier

​ LoadLoadBarrier ​ volatile 读操作 ​ LoadStoreBarrier

  • 硬件OS层面

    windows lock 指令实现 或是 MESI实现

面试new Object() 6连问

  • 1.解释对象的创建过程

    该问题结合上篇博客:JVM系列【3】Class文件加载过程不难回答出来。

    class loading

    class linking (vertification prepraration resolution)

    class initiazing

    new 申请内存空间

    成员变量赋初始值

    调用构造方法 :成员变量赋初始值;执行构造方法语句,super()父类构造。

  • 2.对象在内存中的存储布局

    对象在内存中布局分普通对象和数组对象。

    普通对象4部分:对象头markword(8字节)、ClassPointer指针(4或8字节)、实例数据、padding对齐为8的倍数。

    数组对象5部分,和普通对象类似,但中间是数组长度4字节和具体的数组数据。

JVM系列【4】内存模型_第3张图片

  • 3.对象头具体包括什么

    对象头markword(8字节)具体内容和对象锁状态有关系,其中最高位2位是锁状态中,最低3位用作锁标志位,中间4位是GC年龄,如下。

    JVM系列【4】内存模型_第4张图片

  • 4.对象怎么定位

    通过句柄池和直接指针,具体参考:访问对象两种方式--句柄和直接指针

  • 5.对象怎么分配?

    对象的分配其实和垃圾回收GC有关系,后续总结GC详细讲。

JVM系列【4】内存模型_第5张图片

  • 6.Object o = new Object() 在内存中的占用多少个字节

    16个字节,根据第2点的内存布局可以算出。

知识分享,转载请注明出处。学无先后,达者为先!

你可能感兴趣的:(JVM系列【4】内存模型)