JMM规范
硬件层数据一致性
- 协议:intel使用MESI Cache一致性协议。有多种缓存协议
- 参考文章:https://www.cnblogs.com/z00377750/p/9180644.html
- 缓存锁实现之一,但是有些无法被缓存的数据或者跨越多个缓存行的数据依然必须使用总线锁
- 读取缓存以cache line 为单位,目前64bytes
- 位于同一行的缓存行数据,被两个不同CPU锁定,产生相互影响的伪共享问题
- 解决使用缓存行的对齐能够提高效率
- 合并写技术:WCBuffer(4个字节,很快)
- 参考文章:https://www.cnblogs.com/liushaodong/p/4777308.html
乱序问题
CPU为了提高指令执行效率,会在一条指令执行过程中(比如去内存读数据慢:100倍),去同时执行另一条指令,前提是两条指令没有依赖关系
有序性保障
- CPU内存屏障
- sfence:在sfence指令前的写操作,必须在sfence指令后的写操作前完成
- lfence:在lfence指令前的读操作,必须在lfence指令后的读操作前完成
- mfence:在mfence指令前的读写操作,必须在mfence指令后的读写操作前完成
- intel lock汇编指令
- 原子指令,如x86上的lock指令是一个Full Barrier 执行时会锁住内存子系统来确保执行顺序,甚至跨多个CPU,Software Locks通常使用了内存屏障或原子指令来实现变量的可见性和保持程序顺序
volatile实现细节
-
字节码层面
- 增加ACC_VOLATILE
-
JVM层面
- volatile内存区前后都加屏障
StoreStoreBarrier volatile写操作 StoreLoadBarrier LoadLoadBarrier volatile读操作 LoadStoreBarrier
-
OS和硬件层面
- hsdis :HotSpot Dis Assembler(反汇编)
- windows lock实现
synchronized实现细节
-
字节码层面
ACC_SYNCHRONIZED
monitorenter monitorexit monitorexit(异常时退出)
-
JVM层面
C、C++ 调用了操作系统提供的同步机制
-
OS和硬件层面
X86:lock cmpxchg XXX
对象结构
使用Java Agent测试Object的大小
java -XX:+PrintCommandLineFlags -version
在JDK1.5以后,我们可以使用agent技术构建一个独立于应用程序的代理程序(即为Agent),用来协助监测、运行甚至替换其他JVM上的程序。使用它可以实现虚拟机级别的AOP功能。
Agent分为两种,一种是在主程序之前运行的Agent,一种是在主程序之后运行的Agent(前者的升级版,1.6以后提供)
普通对象
- 对象头markword 8
- ClassPointer指针:-XX:+UseCompressedClassPointer 4 不去开启8
- 实例数据:引用类型:-XX+UseCompressedOops为4 不开启8
- Padding对齐,8的倍数
数组对象
- 对象头:markword 8
- ClassPointer指针同上
- 数组长度:4
- 数组数据
- 对齐 8 的倍数
对象访问方式
- 句柄池
- 在JVM中划分出句柄池:包含对象在堆中的数据地址、方法区中的类型地址,间接访问对象
- 优点:对象引用改变只需在句柄池中、垃圾回收算法快
- 直接指向(HopSpot默认):
- 直接指向JVM堆中的对象引用
- 优点:直接访问对象速度快、寻址时间耗费长