class文件的加载过程
-
loading
- 加载层次 低 --> 高
Custom ClassLoader --> App --> Extension --> Bootstrap - 双亲委派 – 防止内部类被覆盖
低 -> 高,依次在缓存中寻找需要加载的类,有就直接返回;都无,高 -> 低,依次加载类,若都失败,抛出 ClassNotFoundException。 - 自定义类加载器
- 继承ClassLoader
- 重写模板方法findClass
- 加载层次 低 --> 高
-
linking
- verification :校验文件是否符合JVM规范
- preparation:给静态变量赋初始值
- resolution :解析,将常量池符号引用转为内存地址
-
initializing :静态变量赋值
java内存模型 JMM
- cpu运行速度 高 -> 低
- L0(寄存器) > L1 > L2 > L3(所有cpu共享)
- cache line
- MESI缓存一致性协议
- M :修改,本线程修改过
- E:独占,刚修改后为独占状态
- S:共享,与其他线程数据一致
- I:无效,一个线程改过后,其他线程此数据无效
- cache line概念
- 读取缓存以 cache line 为单位,64个字节
- false sharing(伪共享)
- 同一个cache line 中多个数据被不同的线程锁定,产生相互影响。
- 例:cache line 中 A,B两个数据被线程A,线程B共享;线程A修改A数据,会导致线程B要重新去主存中加载cache line。
- 解决
- 使用缓存行对齐,能提升一定的效率。
- 同一个cache line 中多个数据被不同的线程锁定,产生相互影响。
- MESI缓存一致性协议
乱序问题
cpu为了提高指令的运行速度,会在执行一条指令的过程中,执行另一条指令(前提这两条指令没有依赖关系)。
如何保证指令的有序性
- 硬件内存屏障
sfence :写操作不可指令重排
lfence : 读操作不可指令重排
mfence :读写操作不可指令重排
- jvm级别规范
LoadLoad屏障 :指令前的读操作完毕才能执行指令后的读操作
StoreStore屏障:指令前的写入数据对其他处理器可见
LoadStore屏障:指令前的读操作完毕才能执行指令后面的写操作
StoreLoad屏障:指令前的写操作对其他处理器可见才能执行指令后的读操作
volatile实现细节
- 字节码层级 --> ACC_VOLATILE
- JVM层级 --> volatile读写都加屏障
StoreStore Barrier
volatile 写
StoreLoad Barrier
LoadLoad Barrier
volatile 读
LoadStore Barrier
- OS和硬件层级
windows lock 指令实现 | MESI实现
synchronized实现细节
- 字节码层级
- 方法:ACC_SYNCHRONIZED
- 同步代码块:monitorenter monitorexit
- JVM层级 --> C C++ 调用了操作系统提供的同步机制
- OS和硬件层级 --> lock cmpxchg / xxx
对象内存布局
对象创建过程
123将class文件load到内存,456初始化对象
- class loading
- class linking
- verification:校验是否符合JVM规范
- preparation:静态变量赋默认值
- resolution:解析,常量池符号引用转为地址引用
- initializing: 静态变量赋值,调用静态语句块
- 申请内存空间
- 成员变量赋默认值
- 调用构造方法
- 顺序给成员变量赋值
- 执行构造语句方法
对象在内存中的存储布局
观察虚拟机配置
java -XX:+PrintCommandLineFlags -version
- 普通对象
- markword (对象头) 8字节
- Classpointer(指针,指向类)
- 上图 1开启为4字节 不开启为8字节
- instance
- 数据为引用类型:上图 2开启为4字节,不开启为8字节
- padding 对齐,不足8的倍数自动补齐
- 数组对象
比普通对象多出一个数组长度 --> 4字节
对象头 markword
- 1bit 表示是否为偏向锁,2bit 表示锁标志位
- 4bit 表示分代年龄
- 31bit 表示hashCode
GC最大年龄
markword只有4bit表示分代年龄,最大15