JVM——GC详解

理论模型

需要回收的对象的判断

引用计数法

在对象中添加引用计数器,每当有一个地方引用它时,计数器值就加一;当引用失效是,计数器值减一。
任何时刻,计数器为0,说明该对象不再被使用。
如果出现循环引用的问题,引用计数法很难解决。

可达性分析

通过一系列的GCRoot根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索。
如果某个对象没有任何路径可以到GCRoot集合,则说明此对象不可能再引用。
GCRoot根:

  • 栈帧中,本地变量表引用的对象,(各个线程被调用的方法,堆栈中使用到的参数,局部变量,临时变量)。
  • 在方法区中,类静态属性引用的对象,譬如Java类的引用类型静态变量。
  • 在方法区中,常量引用的对象,譬如字符串常量池里的引用。
  • 在本地方法栈中,JNI引用的对象。
  • Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象。
  • 所有被同步锁(Synchronized关键字)持有的对象。

特例 finalize() 方法。

分代收集理论

收集器应该讲Java堆划分出不同的区域,然后将回收对象依据其年龄分配到不同的区域存储。

  • MinorGC:对年轻代进行垃圾收集
  • MajorGC:对老年代进行垃圾收集
  • FullGC:全域的垃圾收集

标记-清除算法

首先标记出所有需要回收的对象,在标记完成后,统一回收所有被标记的对象。
也可以标记存活的对象,统一回收所有未被标记的对象。
缺点:
执行效率不稳定,如果Java堆中包含大量对象,而且大部分需要被回收,这是就要进行大量的标记和回收。
内存碎片化问题,标记-清除后产生大量不连续的内存碎片

标记-复制算法

半区复制:将可用内存划分为大小相同的两块,每次只使用其中的一块。
当一块的内存用完,就将还活着的对象复制到另一块上去,然后再把已经使用的内存空间一次性清理掉。
标记复制算法的优化:因为大部分时候,年轻代中的对象大部分都都朝生夕死的。
年轻代= Eden+ 2Survivor(from区 + to区);
Eden区与from/to区:8:1;
发生MiniorGC:Eden区使用标记复制算法复制到from区,to区域也复制到from区域,此时存活的对象都在from区。

标记-整理算法

标记与其他标记算法一样,后续步骤是让所有存活的对象都向内存空间一端移动,然后直接清理掉边界之外的空间。

内存分配与回收策略

对象优先在Eden分配。

大多数情况下,对象生成之后,直接在Eden区分配空间。当Eden区域不够时,发起MiniorGC。

大对象直接进入老年代

大对象就是需要连续内存空间存储的对象,最典型的就是字符串。如果存在大量的大对象,就会发生频繁的GC,但是如果大对象反复在年轻代标记-复制,会耗费大量的CPU资源,而且还会增大发生FullGC的概率。
设置大对象阈值:-XX:PretenureSizeThreadhold。

长期存活的对象进入老年代

由对象头中的对象年龄,作为判断依据。Survivor中,每在一次MiniorGC,或FullGC中存活下来,那么对象的年龄加1。默认当对象年龄达到一定程度(默认15),就会晋升到老年代中。
设置晋升老年代的年龄阈值:-XX:MaxTenuringThreadhold。

动态年龄对象判断

如果在Survivor空间中相同年龄的所有对象的大小总和超过Survivor区空间的一半,则年龄大于或等于该年龄的对象就可以直接进入老年代。

空间分配担保机制

发生MiniorGC之前:
判断 老年代剩余的连续空间 和 年轻代所有对象大小的总和。
判断是否设置参数:-XX:HandlePromotationFailure允许担保失败。
判断 老年代剩余的连续空间 和 历次年轻代经历MiniorGC之后进入老年代的平均大小。
在这里插入图片描述

实际垃圾收集器

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

CMS(Serial Old作为备份方案)

标记清除算法。

CMS收集器是一种以获取最短回收停顿时间为目标的收集器。
常用在网站或者响应速度快的系统中。

  • 1)初始标记CMS initial mark 标记GCRoot能直接关联到的对象
  • 2)并发标记CMS concurrent mark 从GCRoot直接关联的对象开始遍历整个对象图。
  • 3)重复标记CMS remark 修正并发标记期间,由于对象发生的改动,导致标记需要作出调整。
  • 4)并发清除CMS concurrent sweep 清理掉标记已经死亡的对象。
    初始标记和并发标记这两个步骤仍然会发生“Stop the world”。
    在这里插入图片描述
    三大缺点:
  • 对处理器资源非常敏感。CMS对处理器核心数量是有要求的。当处理器数量超过4个的时候,占用的处理器资源会随着处理器数量的增加而减少。
  • 无法处理浮动垃圾。在并发标记和并发清理阶段,由于此时用户的其他线程仍然在执行,那么就会不断地有新的对象产生,但是这一部分对象是出现在标记以后,,CMS无法在这次回收中回收掉这些垃圾对象,只好留待下一次回收清理。(这样的垃圾称为浮动垃圾)。
  • 标记-清除算法的通用缺点,会产生大量的空间碎片。

G1垃圾收集器(老年代与年轻代都可以使用)

面向局部收集和基于Region的内存布局。
停顿时间模型:在指定时间长度M毫秒的时间片段内,消耗在垃圾收集上的时间大概率不超过N毫秒。

  • G1不再以新生代,老年代作为目标范围,而是面向堆中的任何部分;衡量标准不再是分代,而是回收利益(MixedGC)
  • G1不再坚持固定大小以及固定数量的分代区域划分;把连续的Java堆划分为多个大小相等的独立区域(Region);
  • 每一个Region都可以根据需要,扮演新生代和Eden空间,Survivor空间,或者老年代空间。
  • 收集器能对扮演不同角色的Region采用不同的策略处理
  • Region中Humongous区域专门存储大对象(超过Region大小的一半)
  • 回收前,Region按照回收利益大小排序,优先处理回收利益大的(在特定的时间内)

收集步骤:

  • 初始标记 InitialMarking:标记GCRoot能直接关联到的对象,并且修改TAMS指针的值
  • 并发标记 Concurrent Marking:GCRoot开始对堆中的对象进行可达性分析,重新处理SATB记录
  • 最终标记 Final Marking:对用户线程做另一个短暂的暂停,用于处理并发阶段结束后仍遗留下来的最后的少量的SATB记录。
  • 筛选回收 Live Data Counting and Evacuation:更新Region的统计数据,对各个Region的回收价值和成本进行排序,指定回收计划。
    在这里插入图片描述注:
  • TAMS:(Top at Mark Start)每个Region上设置两个名为TAMS的指针
  • SATB:原始快照方法
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值