3.1概述
3.2对象已死吗
3.2.1引用计数法
实现简单、判定效率高
无法解决循环引用的问题
主流虚拟机没有采用
3.2.2可达性分析算法
通过一系列称作“GC Roots”的对象作为起始点,向下搜索,搜索走过的路径成为引用链,当一个对象到GC Roots没有任何引用链相连,则证明不可用
可作为GC Roots的对象
虚拟机栈(栈帧中的本地变量表)中引用的对象
方法区中类静态属性引用的对象
方法区中常量引用的对象
本地方法栈中JNI(即一般所说的native方法)引用的对象
3.2.3再谈引用
强引用:只要引用存在,垃圾收集器就不会回收
软引用(SoftReference):有用但非必须,系统在发生内存溢出之前进行二次回收
弱引用(WeakReference):非必须对象,只能生存到下一次垃圾收集发生之前
虚引用(PhantomReference):又称幽灵引用或者幻影引用,对对象的生存时间无影响,也无法通过虚引用获得对象的实例,唯一目的是这个对象被虚拟机回收的时候收到一个系统通知
3.3.4生存还是死亡
不可达对象两次标记后才可以宣告死亡
第一次标记筛选判断是否需要执行finalize()方法
当对象没有覆盖finalize()或者已经被虚拟机调用,则不需要执行
有必要执行,则放到F-Queue的队列中,稍后由虚拟机自建的、低级别的线程Finalizer去执行———触发操作,不保证运行结束
finalize()方法是对象逃脱死亡的最后一次机会
3.3.5回收方法区
回收废弃常量:没有任何地方引用
回收无用的类
同时满足以下三个条件,”可以“回收
堆上没有该类的任何实例
加载该类的ClassLoader已经被回收
该类的java.lang.Class对象没有被任何地方引用,无法通过发射获取该类的实例
在大量使用发射、动态代理、CGLib等ByteCode框架、动态生成JSP以及OSGI这类频繁自定义Classloader的场景都需要具备类卸载功能,以保存永久代不会溢出
3.3垃圾收集算法
3.3.1标记-清除算法
算法分为标记和清除两个阶段,首先标出需要回收的对象,标记完成后统一回收
不足:效率,标记和清除效率都不高;空间,产生内存碎片
3.3.2复制算法
将内存按容量分为大小相等的两块,每次只使用一块
当一块用完了,将活着的对象复制到另一块上,然后把已使用过的内存清理掉
不足:内存缩小一半,造成内存浪费
3.3.3标记-整理算法
适合老年代
3.3.4分待收集算法
根据存活周期内存划分
3.4HotSpot的算法实现
3.4.1枚举根节点
可作为GC Roots的节点主要在全局性引用(常量和类静态属性)和执行上下文(帧栈中的本地方法表中)
Stop The world
3.4.2安全点
3.4.3安全区域
3.5垃圾收集器
3.5.1Serial收集器
最基本,发展最悠久的
单线程收集(一个CPU,一个收集线程)
暂停所有其他工作,知道收集结束
Client模式下的默认收集器
3.5.2ParNew收集器
Serial收集器的多线程版
多条线程进行垃圾收集
Server模式下的默认收集器
只有Serial和ParNew和CMS能够配合使用
3.5.3Parallel Scavenge收集器
新生代收集器,采用复制算法
并行的多线程收集器
目的达到一个可控制的吞吐量
3.5.4 Serial Old收集器
单线程
使用标记整理算法
主要目的在给client模式下的虚拟机使用
server模式下用途
jdk1.5及其以前的与Parallel Scavenge配合使用
作为CMS的后备预案
3.5.5 Parallel Old收集器
Parallel Scanvenge的老年代版本
使用多线程和标记整理
JDK1.6中开始使用
3.5.6CMS收集器
以获取最短停顿时间为目标
基于标记清除算法
四个步骤
初始标记
并发标记
重新标记
并发清除
优点:并发收集、低停顿
缺点:对CPU资源敏感;无法处理浮动垃圾;空间碎片
3.5.7G1收集器
面向服务端应用的垃圾收集器
特点
并行与并发
分代收集
空间整合
可预测的停顿
把JAVA堆分为多个Region,根据价值大小(回收获得的空间和所需要时间的经验值)回收
3.5.8理解GC日志
3.5.9垃圾收集器参数总结
3.6内存回收和分配策略
3.6.1对象优先在Eden区分配
当没有足够的Eden时,虚拟机进行一次Minor GC
打印内存回收日志:-XX:PrintGCDetails
Suvivor不足,通过分配担保机制进入老年代
3.6.2大对象直接进入老年代
通过设置参数-XX:PretenureSizeThreshold,大于该参数的垃圾收集的时候直接进入老年代,避免在Eden区和两个个Survivor进行大量的内存复制
3.6.3长期存活的对象进入老年代
虚拟机为每个对象定义了年龄计数器
年龄阈值-XX:MaxTenuringThreshold
3.6.4动态对象年龄判断
在Survivor区相同年龄大小的所有对象大小的总和大于Survivor的一半,则年龄大于或等于该年龄的对象直接进入老年代
3.6.5空间分配担保
第三章:垃圾收集器与内存分配策略
参考文献:
[1] 深入理解Java虚拟机 第二版 --周志明