GC原理简述
GC原理简述
什么是垃圾
没有任何引用指向的一个对象,或者只是循环引用没有外部引用的多个对象。
如何定位垃圾
-
reference count (引用计数)
每次被引用计数器就+1,释放的时候计数器-1 。
-
root searching (根可达)
定义某些根对象,只要根对象指向的对象那么就不是垃圾,其它的对象都是垃圾。
JAVA用的就是根可达算法,JAVA定义的根有一下几类:
-
常见的回收算法
-
Mark Sweep (标记清除)
处理方式:标记垃圾,然后直接回收。
优缺点:速度快,但是容易产生内存碎片
-
Copying (拷贝)
处理方式:将存活对象复制到别的内存中,并重新排列。然后将之前的内存整块清除。
优缺点:速度快,不会产生内存碎片,但是需要两倍的内存空间
-
Mark Compact(标记压缩)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tBkFMd1Q-1605580242555)(media/c6ca555f1f523098e6f085f9fd56a193.png)]
处理方式:标记垃圾,然后将存活对象复制到一起,清除其它的垃圾。
优缺点:没有碎片,不需要额外的内存空间,但是效率稍微比Copying低一些。
-
JAVA的分代算法
由于每个算法都有优劣,所以JAVA 8
及以前的版本使用了分代算法,结合不同的方法来达到提高效率的目的。
分代模型:新生代 + 老年代 + 永久代(1.7)/ 元数据区(1.8)
永久代和元数据区的区别:
-
永久代使用时必须指定内存大小,可能会产生内存溢出;元数据区可以不指定内存大小,只受限于物理内存。
-
永久代存放在堆内存中,元数据区不在堆内存中
JAVA的栈和堆
栈:每个线程有自己的一个栈空间,执行每个方法的时候都会在栈空间中申请一个栈帧每个栈帧包括局部变量区和操作数栈,用于存放此次方法调用过程中的临时变量、参数和中间结果。栈帧执行完后空间自动回收。
堆:所有通过new创建的对象都是存放在堆内存中,堆内存不会自动回收,所以GC针对的就是堆空间。
Java分代算法的堆内存模型
新生代:Eden + s0 + s1 默认比例为 8:1:1,新生代和老年代的比例为
1:3,这些比例都是官方通过不断实践确认的,新生代的对象每次回收时80%
90%的对象会被回收。
YGC就是指新生代发生的GC:
每当Eden区内存使用完了以后就会触发YGC
第一次YGC会把 Eden中存活的对象copying到s0中
第二次YGC会把 Eden + s0 中存活的对象copying 到s1
第三次YGC Eden + s1 -> s0
当 s0或s1存不下的时候,或者活过一定次数YGC却没有被回收的对象(年龄)
会进入到old区
老年代:存放的是不易回收的对象,区域满了进行一次Full GC (FGC),Full
GC用的算法是MarkCompact
,所需要的时间是比较长的,所以我们调优的目标是尽量减少Full GC
补充概念:Minor GC = YGC
Major GC = FGC
垃圾回收器
JAVA发展到目前为止一共产生了10种垃圾回收器
Serial + Serial Old :
串行回收,触发GC时,所有线程停止(Stop The
World),垃圾回收算法执行完后,线程恢复执行
ParNew + CMS:
ParNew并行回收,由于PS不能和CMS一起使用,所以设计了ParNew可以配合CMS使用
CMS:并发的,垃圾回收和应用程序同时运行,降低STW的时间(200ms),标记算法为三色标记法
Parallel Scavenger + Parallel Old :
并行回收,效率高于Serial,触发GC时,所有线程停止,垃圾回收算法执行完后,线程恢复执行
G1: 摒弃了分代算法,采用分区算法(Region),能将STW时间降低到10ms以内。
物理上不分代,逻辑上分代,回收时会对区域进行逻辑上的定义,但是这个定义并不是固定的,会随着垃圾回收的过程而变化,分区大小固定,可以由用户指定大小。
ZGC:
同样是Region,逻辑上也不分代分区大小不固定100ms触发一次GC,找到较满的区域回收。能够将STW时间降低到1ms。
Shenandoah:开源社区开发的,类似ZGC。
,找到较满的区域回收。能够将STW时间降低到1ms。
[外链图片转存中…(img-FAls0cSC-1605580242565)]
Shenandoah:开源社区开发的,类似ZGC。
Epsilon: Oracle开发人员,调试JDK的过程中使用的,不做任何事情。