GC垃圾回收机制

  • Post author:
  • Post category:其他


一、

GC

算法

1.标记-清除算法(Mark Sweep):    缺:效率低、有内存碎片

a.标记阶段:遍历所有GC roots,将gc roots引用链可达的对象标记为存活;

b.清理阶段:遍历堆中所有对象,清理未被标记的对象。

2.复制算法:先根据引用链做可达性分析,把活着的对象复制过去,然后把原区域清空。

优:解决内碎片问题;存活率低时效率高

缺:浪费内存;对象存活率高时效率低下

3.标记-整理算法:移动所有存活对象,按地址排序,把后面的清除。 效率也不高

4.分代收集:新生代采用复制算法(存活率低)、老年代采用标记整理算法(存活率高)。

原因:大部分对象的生命周期很短,极少部分可能会存活很久,这部分对象每次gc反复标记处理,浪费资源。

5.判断是不是垃圾:    引用记数法(循环引用时内存泄露);

可达性分析:从gc roots开始通过引用关系遍历对象图,能被引用链遍历到的认为存活(基本都是用这种方式)

6.

GC roots

:引用链的最顶级,

是一组必须活跃的引用

,不是对象! minor gc比full gc的gc roots还要更多,因为要从old gen里面额外拿gc roots.      gc roots有哪些: a.活跃的栈帧中的引用对象;  b.方法区中静态属性指向堆中对象的引用;  c.本地方法栈中JNI(native方法)的引用

7.stop-the-world:gc的时候,停掉除gc外的java线程。

二、

gc收集器

1. Serial / Serial old:单线程;复制算法 / 标记整理算法;停顿时间长

ParNew:多线程;新生代的复制算法

Parallel Scavenge / Parallel old:多线程(paralle:并行),复制算法 / 标记整理算法;

注重吞吐量

: T运行 / (T运行+Tgc)

CMS:多线程;

老年代



标记m清除s

算法;   优:

停顿时间短

;   缺:

吃cpu资源

,有

内存碎片

,清理阶段会产生新垃圾(

浮动垃圾

)

cms执行过程: 1.STW标记gc roots引用的对象;  2.和用户线程一起并发标记其他对象;

3.STW标记第二步新增的对象;  4.和用户线程一起并发清理垃圾。


G1

:区域化、并发、增量式垃圾回收器。  整体看是标记整理,局部(两个region之间)是复制算法。


引入分区的思路,弱化了分代的概念。 整个

堆内存被分为许多大小相等的连续区域Region,维护一个优先列表,记录每个Region的价值,价值是由之前这个区域GC所获空间大小和GC所需时间来决定的(优先列表类似逻辑上的新生代/老年代?)。

工作过程类似CMS,第四步清理有区别(根据优先级控制时间),增加remembered set保存对象引用的调用信息;

最后一步的清理阶段基于标记-整理和复制算法实现。

优:

性能好



无碎片



G1的gc耗时可控

:根据预设的gc耗时,优先回收高价值的region.

2.G1和CMS的对比: 1.G1无内存碎片,CMS有   2.G1的gc时间可控   3.CMS只回收老年代,G1无物理分代

3.



JDK11中的ZGC



:专注于

减少暂停时间

的同时

压缩堆

。 优:无分代概念、无碎片、时间可控、停顿时间跟堆大小没关系

a.并发执行的保证机制,就是


Colored Pointer


(着色指针:将信息存储在指针/引用上) 和


Load Barrier


(读屏障)

b.像G1一样划分Region,但更加灵活:g1的region大小固定,ZGC 可以有2MB,32MB,N× 2MB,大对象放大region

c.

STW

标记gcRoots(此操作不标记堆中的对象,所以停顿时间跟堆大小没关系,但是跟线程数量和线程内对象数量有关);  并发标记;  复制到另一个region(老区域可以成为新的复制to区);    Remap修正指针:将指针都指向新地址(上一阶段的Remap和下一阶段的Mark是同时操作的,节省遍历图的开销);

d. 没有g1的RememberSet和写屏障的开销:划分Region并不是为了增量回收,每次都会对所有Region进行回收,所以也就不需要这个占内存的RememberSet了;又因为它暂时

没有分代

,所以完全没有Write Barrier。

三、为什么要关注gc?

知道垃圾是怎么回收的,写代码的时候减少长生命周期对象的使用、减少大对象的创建;监控如果频繁gc则要快速定位原因balabala..

四、线上频繁full gc怎么办?


查看gc日志判断gc原因

;合理调参分配各个区域的大小;增加Survivor区来防止更多的对象进入老年代

五、线上用的:

G1:   堆总内存:12G

Eden区:0~8G;

OldGen:1~6G;

survivor区:平均100多M;

元空间metaSpace: 平均100多M;

频率:   youngGC:每分钟0~2次,每次100ms左右.(在做youngGC时,OldGen区域也会相应减少,因为G1没有物理分区新生代老年代)      没有fullGC



版权声明:本文为qq_39082976原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。