建设银行住房公积金卡网站,公司注册的流程和条件,网站开发公司erp,深圳网络推广公司哪家好目录 垃圾回收器1 Serial收集器2 Parallel收集器3 ParNew收集器4 CMS收集器5 G1回收器三色标记算法标记算法的过程三色标记算法缺陷多标漏标 垃圾回收器
垃圾回收机制#xff0c;我们已经知道什么样的对象会成为垃圾。对象回收经历了什么——垃圾回收算法。那么谁来负责回收垃… 目录 垃圾回收器1 Serial收集器2 Parallel收集器3 ParNew收集器4 CMS收集器5 G1回收器三色标记算法标记算法的过程三色标记算法缺陷多标漏标 垃圾回收器
垃圾回收机制我们已经知道什么样的对象会成为垃圾。对象回收经历了什么——垃圾回收算法。那么谁来负责回收垃圾呢
1 Serial收集器
-XX:UseSerialGC -XX:UseSerialOldGC
单线程执⾏垃圾收集收集过程中会有较⻓的STWstop the world在GC时⼯作线程不能⼯作。虽然STW较⻓但简单、直接。
新⽣代采⽤复制算法⽼年代采⽤标记-整理算法。 由于Serial垃圾回收器是单线程的因此它的优点是简单且占用资源较少;它适用于小型应用程序例如移动应用程序和桌面应用程序。
2 Parallel收集器
-XX:UseParallelGC,-XX:UseParallelOldGC
使⽤多线程并行进⾏GC会充分利⽤cpu但是依然会有stw这是jdk8默认使⽤的新⽣代和⽼年代的垃圾收集器。充分利⽤CPU资源吞吐量⾼。
新⽣代采⽤复制算法⽼年代采⽤标记-整理算法。 Parallel垃圾回收器适用于中等大小的应用程序特别是那些需要高吞吐量的应用程序例如: Web应用程序和大规模企业应用程 序。
3 ParNew收集器
-XX:UseParNewGC
⼯作原理和Parallel收集器⼀样都是使⽤多线程进⾏GC但是区别在于ParNew收集器可以和CMS收集器配合⼯作。主流的方案
ParNew收集器负责收集新生代CMS负责收集老年代。 4 CMS收集器
-XX:UseConcMarkSweepGC
⽬标尽量减少stw的时间提升⽤户的体验。真正做到gc线程和⽤户线程⼏乎同时⼯作。CMS采⽤标记-清除算法。
此处标记的是有用的对象。 初始标记暂停所有的其他线程(STW)并记录gc roots直接能引⽤的对象。 例线程栈帧的局部变量表中有个引用指向堆空间对象A堆空间变量又引用了另一个对象B则只记录A不算B。 并发标记从GC Roots的直接关联对象开始遍历整个对象图的过程这个过程耗时较⻓但是不需要STW可以与应用线程⼀起并发运⾏。这个过程中⽤户线程和GC线程并发可能会有导致已经标记过的对象状态发⽣改变所以下一步需要重新标记 最后一句话是说会造成标记的遗漏 重新标记为了修正并发标记期间因为⽤户程序继续运⾏⽽导致标记产⽣变动的那⼀部分对象的标记记录这个阶段的停顿时间⼀般会⽐初始标记阶段的时间稍⻓远远比并发标记阶段时间短。主要⽤到三⾊标记⾥的算法做重新标记。 并发清理开启⽤户线程同时GC线程开始对未标记的区域做清扫。这个阶段如果有新增对象会被标记为黑色不做任何处理。最终被标记为白色的都是垃圾 并发重置重置本次GC过程中的标记数据。 总结
这几步中最费时间的是并发清理所以采用了并发处理初始标记和重新标记两处采用STW形式因为标记的速度很快重新标记采用STW模式因为是最后一步标记要确保标记到的必须都是用到的
5 G1回收器
用于大对象的回收且jdk8版本对G1不是很完整
三色标记算法
标记算法的过程
再上述cms收集器中采用到的算法就是三色标记法。
三色标记法会将内存中的对象分为白、灰、黑三种颜色具体标记过程如下 根据可达性分析算法从 GC Roots 开始进行遍历访问。初始状态所有的对象都是白色的只有 GC Roots 是黑色的。 初始标记阶段GC Roots 标记直接关联对象置为灰色。 并发标记阶段扫描整个引用链。 没有子节点的话将本节点变为黑色。 有子节点的话则当前节点变为黑色子节点变为灰色。 重复并发标记阶段直至灰色对象没有其它子节点引用时结束。
扫描完成此时黑色对象就是存活的对象白色对象就是已消亡可回收的对象。
即A、D、E、F、G可达也就是存活对象B、C、H不可达可回收的对象。
最终三种颜色对应的状态如下
三色标记算法缺陷
三色标记算法由于在并发标记阶段的时候因为用户线程与 GC 线程同时运行有可能会产生多标或者漏标。
多标
假设已经遍历到 E变为灰色了此时应用执行了 objD.fieldE null (D → E 的引用断开)。
D → E 的引用断开之后E、F、G 三个对象不可达应该要被回收的。然而因为 E 已经变为灰色了其仍会被当作存活对象继续遍历下去。最终的结果是这部分对象仍会被标记为存活即本轮 GC 不会回收这部分内存。
这部分本应该回收但是没有回收到的内存被称之为浮动垃圾。浮动垃圾并不会影响应用程序的正确性只是需要等到下一轮垃圾回收中才被清除。
另外针对并发标记开始后的新对象通常的做法是直接全部当成黑色本轮不会进行清除。这部分对象期间可能会变为垃圾这也算是浮动垃圾的一部分。
漏标
假设 GC 线程已经遍历到 E变为灰色了此时应用线程先执行了
var G objE.fieldG; objE.fieldG null; // 灰色E 断开引用 白色G objD.fieldG G; // 黑色D 引用 白色G此时切回到 GC 线程因为 E 已经没有对 G 的引用了所以不会将 G 置为灰色尽管因为 D 重新引用了 G但因为 D 已经是黑色了不会再重新做遍历处理。
最终导致的结果是G 会一直是白色最后被当作垃圾进行清除。这直接影响到了应用程序的正确性是不可接受的。
漏标只有同时满足以下两个条件时才会发生
一个或者多个黑色对象重新引用了白色对象即黑色对象成员变量增加了新的引用。灰色对象断开了白色对象的引用直接或间接的引用即灰色对象原来成员变量的引用发生了变化。
也有方法可以解决
需要在上面三个步骤中任意一个中将对象 G 记录起来然后作为灰色对象再进行遍历即可。比如放到一个特定的集合等初始的 GC Roots 遍历完并发标记再重新标记阶段对该集合的对象遍历即可重新标记。
var G objE.fieldG; // 1.读objE.fieldG null; // 2.写objD.fieldG G; // 3.写