此文已由做者赵计刚薪受权网易云社区发布。html
欢迎访问网易云社区,了解更多网易技术产品运营经验。算法
一、G1安全
说明:服务器
从上图来看,G1与CMS相比,仅在最后的"筛选回收"部分不一样(CMS是并发清除),实际上G1回收器的整个堆内存的划分都与其余收集器不一样。并发
CMS须要配合ParNew,G1可单独回收整个空间spa
原理:.net
G1收集器将整个堆划分为多个大小相等的Region线程
G1跟踪各个region里面的垃圾堆积的价值(回收后所得到的空间大小以及回收所需时间长短的经验值),在后台维护一张优先列表,每次根据容许的收集时间,优先回收价值最大的region,这种思路:在指定的时间内,扫描部分最有价值的region(而不是扫描整个堆内存),并回收,作到尽量的在有限的时间内获取尽量高的收集效率。设计
运做流程:orm
初始标记:标记出全部与根节点直接关联引用对象。须要STW
并发标记:遍历以前标记到的关联节点,继续向下标记全部存活节点。
在此期间全部变化引用关系的对象,都会被记录在Remember Set Logs中
最终标记:标记在并发标记期间,新产生的垃圾。须要STW
筛选回收:根据用户指定的指望回收时间回收价值较大的对象(看"原理"第二条)。须要STW
优势:
停顿时间能够预测:咱们指定时间,在指定时间内只回收部分价值最大的空间,而CMS须要扫描整个年老代,没法预测停顿时间
无内存碎片:垃圾回收后会整合空间,CMS采用"标记-清理"算法,存在内存碎片
筛选回收阶段:
因为只回收部分region,因此STW时间咱们可控,因此不须要与用户线程并发争抢CPU资源,而CMS并发清理须要占据一部分的CPU,会下降吞吐量。
因为STW,因此不会产生"浮动垃圾"(即CMS在并发清理阶段产生的没法回收的垃圾)
适用范围:
追求STW短:若ParNew/CMS用的挺好,就用这个;若不符合,用G1
追求吞吐量:用Parallel Scavenge/Parallel Old,而G1在吞吐量方面没有优点
二、几点注意
问题1、G1之外的其余收集器在回收垃圾的时候:要不仅是扫描年轻代,要不仅是扫描年老代。在年轻代的回收过程当中,若是旧生代中的对象引用了年轻代的对象,那么咱们只扫描年轻代就不行了,可是因为年老代通常而言是年轻代的3倍大小,若是年轻代、年老代一块儿去扫描的话,效率会急剧降低,这个问题怎么处理?
答:JVM采用remember set来作的这个事儿,当发现一个引用对象被赋值时,JVM发出一个write barrier指令来暂时中断写操做,检查被赋值的引用对象是否是处于年老代,且其引用的对象是否是处于新生代(便是不是年老代对象引用了年轻代对象),若是是,将相关引用信息记录到remember set。以后的扫描,咱们会从根集合+remember set向下进行扫描。(也就是说真正的根集合,是JVM定义的根集合+remember set)
问题2、G1收集器为了作到GC时间可预测,采用扫描部分价值最大的region来实现,那么若是这部分region中的对象被其余region中的对象所引用,那么仅扫描前者可能就不行了,可是若是扫描所有region的话,又没法作到GC时间可预测,效率会大大降低,怎么办?
答:G1同理,为每个region分配一个remember set,当发现一个引用对象被赋值时,JVM发出一个write barrier指令来暂时中断写操做,检查被赋值的引用对象与其引用的对象是否是处于不一样的region(eg.a=b;检查a与b是否是在不一样的region),若是是,将相关引用信息记录到当前region的remember set。以后的扫描,咱们会从根集合+remember set向下进行扫描。
问题3、CMS与G1在并发标记的时候若发部分引用对象的引用关系发生了变化,怎么处理才能让从新标记的时候仅仅扫描出这些变化?
答:在并发标记期间,对象的引用关系若发生了变化,这些相关的记录就会记录到remember set logs;在从新标记阶段,将该logs的信息加入到remember set中去,而后再从remember set去向下trace节点。
免费领取验证码、内容安全、短信发送、直播点播体验包及云服务器等套餐
更多网易技术、产品、运营经验分享请点击。
相关文章:
【推荐】 移动端推广APP防做弊机制之依我见
【推荐】 浅谈代码结构的设计