Java虚拟机极简版
第一部分 走进Java
略过…
第二部分: 内存自动管理机制
1.内存数据区及内存溢出异常
运行时数据区
■线程共享
堆: 创建的对象
方法区: 类信息,常量,静态变量,常量池(符号信用)
■线程私有
虚拟机栈: 局部变量表,操作数栈,动态链接,返回地址
本地方法栈: 为native方法服务
程序计数器: 当前线程所执行字节码行号指示器
■直接内存
Nio直接分配堆外内存,避免Java堆与Native堆来回复制数据
内存溢出异常
OutOfMemoryError:
■堆: Java heap space
■方法区: PermGen space
■栈: StackOverflowError
■直接内存: at sun.misc.Unsafe.allocateMemory(Native Metod)
2.垃圾收集器及内存分配策略
判断对象已死
■引用计数法
无法解决对象相互引用问题
■可达性分析
GcRoots向下搜索走过路径称为引用链,当对象到GcRoots没有任何引用链相连时,判定为可回收
垃圾收集算法
■复制算法: 无碎片,浪费一半内存
■标记整理: 无碎片,不浪费内存
■标记清除: 有碎片,不浪费内存
垃圾收集器
■Serial
■ParNew
■Parallel Scavenge
■Serial Old
■CMS
■Parallel Old
■Parallel 侧重点在于吞吐量优先,吞吐量: 即执行用户代码/Cpu总运行时间,适用于后台任务应用
■CMS 侧重点在于低停顿,适用于及时响应应用,如网站,中台服务等
内存分配与回收策略
■优先分配Eden区
■大对象直接进去老年代: PretenureSizeThreshold
■长时间存活对象进入老年代: MaxTenuringThreshold
■动态对象年龄判断: 年龄相同对象>Survivor一半空间时,进入老年代
■空间分配担保: HandlePromotionFailure,未开启,Minor Gc前判断老年代剩余连续空间大于年轻带对象永和,执行Minor Gc,否则先执行Full Gc;开启后,Minor Gc前判断老年代连续空间是否大于历次年轻带晋升平均值,大于则执行Minor Gc,失败后由Serial Old进行Full Gc,小于则先执行Full Gc
3.Jvm监控及分析工具
监控工具
■Jps: 进程监控
■Jstat: 虚拟机统计信息监控
■Jstatd: 远程监控接口
分析工具
■Jmap: 内存映射工具
■Jstack: 线程跟踪工具
■Jinfo: Jvm配置信息工具
第三部分 虚拟机执行子系统
1.类加载机制
类加载顺序
加载-验证-准备-解析-初始化
类加载器类型
Bootstrap Extention Application User
双亲委派模型
类加载器不会自己去加载类,而是将请求委派给父加载器,每层加载器都是如此,直到父加载器无法加载此类时,子加载器才会自己尝试加载,因此可以保证同一个类在各个加载器环境中都是同一个类。
2.字节码执行引擎
运行时栈帧
本地变量表
操作数栈
动态链接
方法返回地址
字节码执行引擎
计算”1+1”
iconst_1
iconst_1
iadd
istore_0
第四部分 编译优化
1.前期优化
泛型擦除
自动拆箱与遍历
条件编译
2.后期优化
解释执行+编译执行
公共子表达式删除
数组下标检查消除
内联表达式
逃逸分析
第五部分 高效并发
1. 内存线程模型
工作内存+主内存
Volatile 刷新主内存+禁止指令重拍
原子性、可见性、有序性
原子性
read load assign use store write
可见性
一个线程对成员变量的修改,其他线程立即可见
有序性
一个线程中观察,所有操作都是顺序的;一个线程观察另一个线程,所有操作都是无语的,因为指令重拍+工作内存主内存延迟
先行发生原则
在一个线程内,按照程序代码顺序,书写在前面的操作先行发生于书写在后面的操作。
......
2.线程安全
悲观锁
Synchronized
RentrentLock: 可中断,公平
乐观锁: CAS
CAS 操作中包含三个操作数 —— 需要读写的内存位置(V)、进行比较的预期原值(A)和拟写入的新值(B)。我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可
ThreadLocal
内部结构是 ThreadLocalMap,key是当前ThreadLocal对象。当外部设置 threadLocal=null,假设此时当前线程没有结束,仍然持有 ThreadLocalMap 的引用,虽然 threadLocal 设置为空,但ThreadLocalMap依然有引用链,对象可达,当ThreadLocalMap中Entry数据量较大时,可能会产生内存泄漏。
3.锁优化
自旋锁
挂起、恢复线程需要转到内核态完成,给系统完成较大压力,让后面请求锁的线程忙循环(自旋)
自适应自旋锁
自旋时间不再固定,由之前的状态决定
锁粗化、锁消除
StringBuffer
轻量级锁
绝大部分锁在同步周期内是不存在竞争的,轻量级锁使用CAS避免使用互斥量的开销,如果存在竞争,除了互斥量的开销,还有CAS的开销
偏向锁
偏向于第一个获得锁的线程,在接下来执行过程中,没有其他线程获得该锁,持有偏向锁的线程将不再同步