JVM调优必备理论知识-GCCollector

 


准备知识:

存活性分析(怎么找到垃圾):

1.Reference Count引用计数

对象被引用,计数器加一,如果数值减到0,就判断这个对象是垃圾,可以被回收。Objective-C使用这种方式

                    图1-1

2.Root Searching根可达算法

像(图1-2)中A,B,C相互引用的情况,按引用计数都是1,不是垃圾,不会被回收。

但没有其他对象引用这3个对象,在java中是可被回收的垃圾

                                 图1-2

根可达算法:简单地说,如果可以从任何一个已经定义的变量开始,直接或者通过其他对象的引用来访问到某个对象,则该对象是可达的

                                                                                                    图1-3

根对象:

  • 线程变量:从一个main方法运行开始,main线程栈中调用到的其他方法,main线程栈中访问到的对象
  • 静态变量:方法区中的类静态属性引用的对象
  • 常量池:方法区中的常量引用的对象
  • JNI指针:本地方法栈中JNI(Native方法)的引用的对象

主流编程语言均使用根可达算法


 

一、常用的垃圾回收算法

一)Mark-Sweep(标记清除算法)

                                          图2-1

标记阶段:通过根可达算法,将沿途的对象进行标记,标记为存活对象,其他未被标记的对象就是可回收对象。

清除阶段:将全部对象扫描一遍,没有标记的对象都进行清除。

特点:

算法相对简单,在存活对象比较多的情况下,效率比较高

扫描2遍,效率偏低

容易产生碎片

标记清除算法不适合Eden区

二)Copying(拷贝算法)

                                            图2-2

拷贝算法:准备一块新空间,将存活对象都复制到新空间中。然后将旧空间中的对象全部回收。

特点:

适合存活对象较少的情况,适合Eden区

相对于复制清楚算法,节省了存在大量对象时重新扫描一遍内存的开销,且不会产生碎片

但是,增加了内存消耗,实际内存使用率仅50%

HotSpot虚拟机的Serial、ParNew等新生代收集器均采用半区复制分代策略

三)Mark-Compact(标记压缩)

                                            图2-3

标记阶段(与标记清除算法相同):过根可达算法,将沿途的对象进行标记,标记为存活对象,其他未被标记的对象就是可回收对象。

压缩阶段:

  1. 遍历堆, 将所有对象通过计算得到新的地址并保存
  2. 遍历堆, 将所有子对象的地址更新为新的地址, 同时更新根集合中的指针.
  3. 遍历堆, 将对象集体迁移. 指针的问题都解决了, 可以将对象搬到新家了.

常用实现算法:Lisp2算法、Two-Finger算法

特点:

不会产生碎片,不会产生内存减半的问题

扫描2次,需要移动对象,效率偏低

二、垃圾回收器的分代

ZGC之前的算法存在分代,ZGC及以后的算法不在进行分代

垃圾回收器分代,分为逻辑分代和物理分代

其中,G1仅在逻辑分代,物理不分代

                                                   图3-1

物理分代:

区分为:Young(新生代)    Old(老年代)  其中新生代:老年代=1:3

新生代又可以细分为:Eden区,Survivor区(分为survivor0,survivor1,也是常说的from,to)

按垃圾回收发生的范围:

  • 新生代收集Minor GC/Young GC:指目标只是新生代的垃圾收集。
  • 老年代收集Major GC/Old GC:指目标只是老年代的垃圾收集。
  • 整堆收集(Full GC):收集整个Java堆和方法区的垃圾收集。

新创建的对象都会被分配到Eden区(一些大对象特殊处理),这些对象经过第一次Minor GC后,如果仍然存活,将会被移到Survivor区。对象在Survivor区中每熬过一次Minor GC,年龄就会增加1岁,当它的年龄增加到一定程度时,就会被移动到年老代中

当Survivor空间不足以容纳一次Minor GC之后存活的对象时,就需要依赖其他内存区域(实
际上大多就是老年代)进行分配担保(Handle Promotion)

新生代 + 老年代 + 永久代(1.7)Perm Generation/ 元数据区(1.8) Metaspace
   1. 永久代 元数据 - Class
   2. 永久代必须指定大小限制 ,元数据可以设置,也可以不设置,无上限(受限于物理内存)
   3. 字符串常量 1.7 - 永久代,1.8 - 堆
   4. MethodArea逻辑概念 - 永久代、元数据

三、常用的垃圾回收器

 

                                      图4-1                                                                                         图4-2

  1. Serial 年轻代          串行回收
  2. PS 年轻代               并行回收(jdk1.8默认)
  3. ParNew 年轻代      配合CMS的并行回收
  4. SerialOld 
  5. ParallelOld

Serial:当工作时所有工作线程都停止,当工作的时候断开的线程则是垃圾,如果突然加入Serial,则停止,进行垃圾清理

safe point: 线程停止

Serial Old:用在老年代,使用标记压缩的算法,用的也是单线程

Parallel Scavenge:jdk1.8默认垃圾回收器

Parallel Old:标记压缩算法

ParNew: Parallel New,在Parallel Scavenge的基础上做了一些增强,以便可以配合CMS使用

CMS

                                                 图4-3

  1. 初始标记:标记根节点
  2. 并发标记:工作线程和标记同事进行(CMS耗时最长的阶段)
  3. 重新标记:并发标记过程中重新产生的垃圾,重新标记一次
  4. 并发清理:并发清理阶段会产生浮动垃圾

ConcurrentMarkSweep 老年代 并发的, 垃圾回收和应用程序同时运行,降低STW的时间(200ms)
CMS问题比较多,所以现在没有一个版本默认是CMS,只能手工指定
CMS既然是MarkSweep

  1. 就一定会有碎片化的问题,碎片到达一定程度,
  2. CMS的老年代分配对象分配不下的时候,使用SerialOld 进行老年代回收 

并发标记的算法

CMS使用:三色标记算法+incremental Update算法

G1:三色标记算法+SATB算法,主要配合他的Rset来进行

ZGC:用的是颜色指针

©️2020 CSDN 皮肤主题: 创作都市 设计师:CSDN官方博客 返回首页