1 判断对象是否存活
1.1 引用计数法
给对象添加一个引用计数器,有引用+1,引用失效-1;计数器为0的对象是不可再被使用的
缺点:难以解决对象之间相互循环引用的问题
1.2 可达性分析法
通过一系列“GC Roots”对象作为起始点,从这些节点向下搜索,走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,说明此对象不可用。
Note: ref
强引用:new ,强引用存在,垃圾收集器就不会回收掉被引用的对象
软引用:系统发生内存溢出之前,将这些对象列进回收范围进行二次回收
弱引用:被弱引用关联的对象只能生存到下一次垃圾收集发生之前
虚引用:对象被回收时收到系统通知
Note: 无用的类
该类所有的实例都已经被回收,java堆中不存在该类的任何实例
加载该类的ClassLoader已经被回收
该类对应的Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法
2 gc算法
2.1 标记清除
标记完成后同一回收
缺点:
效率问题
空间问题:标记清除之后产生大量不连续的内存碎片
空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而提前触发另一gc动作
2.2 复制
可用内存一分为二,每次使用其一,使用完一块内存之后,将存活对象复制到另一块,然后将已使用过的内存空间清理
只要移动堆顶指针,按顺序分配内存即可
缺点:
将内存缩小为原来的一半
2.3 标记整理
标记过程类似标记清除,后续不是直接对可回收对象清理,而是让所有存活对象向一端移动,然后直接清理掉端边界以外的内存
3 收集器
3.1 Serial
单线程,进行垃圾收集时,必须暂停其他所有的工作线程直至收集结束
3.2 ParNew
Serial的多线程版本,可与CMS配合工作
-XX:+UseConcMarkSweepGC
3.3 Parallel Scavage
目标是达到一个可控制的吞吐量
3.4 Serial Old
CMS收集器的后备方案,并发模式失败时使用
3.5 Parallel Old
配合Parallel Scavage使用
CMS
以获取最短回收停顿时间为目标的收集器;
整个过程分四步:初始表示,并发标记,重新标记,并发清除;其中初始标记和重新标记仍然会STW。初始标记仅是标记GC Roots能关联到的对象,速度很快;并发标记进行GC Roots Tracing;重新标记为了修正并发标记期间因用户程序继续运行导致标记产生变动的一部分对象
总体而言,CMS收集器的垃圾回收过程与用户线程一起并发执行
CMS默认启动的回收线程数是:(CPU数量+3)/4
CMS无法处理浮动垃圾
-XX:CMSInitiatingOccupancyFraction触发百分比
标记清除有大量空间碎片产生
G1
特点:
并行与并发
分代收集
空间整合:整体看标记整理,局部看复制
可预测的停顿
运作步骤:
初始标记
并发标记
最终标记
筛选回收
4 分配回收
4.1 优先eden分配
虚拟机提供-XX:+PringGCDetails这个收集器日志参数,告诉虚拟机在发生垃圾收集行为时打印内存回收日志
4.2 大对象分配
大对象直接分配到老年代,通过 -XX:PretenureSizeThreshold控制阈值
4.3 长期存活对象分配
长期存活的对象进入老年代,通过-XX:MaxTenuringThreshold控制阈值
4.4 空间分配担保
在发生young gc之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,条件成立,young gc是安全的
不成立,虚拟机查看HandlePromototionFailure设置值是否允许担保失败;允许则继续检查老年代最大可用连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,执行一次young gc(有风险);小于或者不允许冒险,执行full gc
4.5 动态对象年龄判定
虚拟机并不是永远要求对象年龄达到最大阈值晋升老年代;
如果在Servivor空间中相同年龄所有对象的大小总和大于Servivor空间的一半,年龄大于等于该年龄的对象就可以直接进入老年代