目录

  • 一、垃圾回收
  • 1.垃圾回收的时机
  • 2.如何判断对象已死
  • (1)引用计数算法(Reference Counting)
  • (2)可达性分析算法
  • 3.JAVA的引用类型
  • (1)强引用
  • (2)软引用
  • (3)弱引用
  • (4)虚引用
  • 4.需要垃圾回收的内存
  • (1)方法区/元空间
  • (2)堆(GC堆)
  • 5.垃圾回收过程:
  • 6.垃圾回收算法
  • (1)标记-清除算法(Mark-Sweep算法)
  • (2)复制算法(Copying算法)
  • (3)标记-整理算法(Mark-Compact算法)
  • (4)分代收集算法
  • 7.STW (Stop The World):GC导致的暂停用户线程
  • 二、垃圾收集器
  • 1.新生代收集器
  • 1.Serial(串行GC)
  • 2.ParNew(并行GC)
  • 3.Parallel Scanvenge(并行GC)
  • 2.老年代收集器
  • 1.Serial Old收集器(串行GC)
  • 2.Parallel Old收集器(并行GC)
  • 3.CMS收集器(并发GC)
  • 4.G1收集器(全区域的垃圾回收器)
  • 三、垃圾回收的时机
  • 1.Minor GC触发条件
  • 2.Majar GC触发的条件


一、垃圾回收

Garbage Collection(GC),Java进程在启动后会创建垃圾回收线程,来对内存中无用的对象进行回收。

1.垃圾回收的时机

(1)System.gc():此方法的调用是建议JVM进行 FGC(Full GC),虽然只是建议而非一定,但很多情况下它会触发 FGC,从而增加FGC的频率。
(2)创建对象时需要分配内存空间,如果空间不足,触发GC。
(3)Object类finilize:作用:对象进行垃圾回收之前,标记对象的可回收状态。

2.如何判断对象已死

(1)引用计数算法(Reference Counting)

给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。 引用计数算法的实现简单,判定效率也很高,在大部分情况下它都是一个不错的算法。但是它很难解决对象之间相互循环引用的问题。

(2)可达性分析算法

通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为GC Roots引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。

java中会触发gc的方法 java gc触发时机_CMS


object5和object6虽然相互引用,但是由于他们到GC Roots都不可达,因此会被判定为可回收的对象。

3.JAVA的引用类型

Java将引用分为强引用(Strong Reference)、软引用(Soft
Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)4种,这4种引用强度依次逐渐减弱。

(1)强引用

指在程序代码之中普遍存在的,类似“Object obj=new Object()”这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象

(2)软引用

用来描述一些还有用但并非必需的对象。对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。在JDK 1.2之后,提供了SoftReference类来实现软引用。

(3)弱引用

用来描述非必需对象的,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。在JDK 1.2之后,提供了WeakReference类来实现弱引用。

(4)虚引用

也称为幽灵引用或者幻影引用,它是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用(PhantomReference)关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知

java中会触发gc的方法 java gc触发时机_老年代_02

4.需要垃圾回收的内存

(1)方法区/元空间

JDK1.7的方法区在GC中一般称为永久代(Permanent Generation)。
JDK1.8的元空间存在于本地内存,GC也是即对元空间垃圾回收
永久代或元空间的垃圾收集主要回收两部分内容:废弃常量和无用的类。此区域进行垃圾收集的“性价比”一般比较低。

(2)堆(GC堆)

java中会触发gc的方法 java gc触发时机_老年代_03

  1. 新生代(Young Generation):又可以分为Eden空间、From Survivor空间、To Survivor空间。
    Eden区和使用的S区,存活对象,复制到留空的S区。GC前后,两块S区的角色发生转变
    新生代的垃圾回收又称为Young GC(YGC)、Minor GC。
    指发生在新生代的垃圾收集动作,因为Java对象大多都具备朝生夕灭的特性,所以Minor GC非常频繁,一般回收速度也比较快
    Eden区:进入对象的条件:创建对象时,优先分配此区域,若此区域空间不足,则出发Minor GC(新生代GC)。
    Survivor区: 一块保存对象, 一块留空。进入对象的条件:触发Minor GC时,留空的S区,会进入GC后存活对象。空间不足, 导致所有对象,进入老年代。
  2. 老年代(Old Generation、Tenured Generation)。
    老年代垃圾回收又称为Major GC。
    空间不足,触发Major GC (老年代GC)
    进入对象的条件:
    (1)大对象直接进入
    (2)长期存活的对象进入老年代一对象年纪> 阈值
    (3) Minor GC时,留空S区空间不足存放GC后的存活对象,所有存活对象,进入老年代。
    指发生在老年代的GC,出现了Major GC,经常会伴随至少一次的Minor GC(但非绝对的,在Parallel Scavenge收集器的收集策略里就有直接进行Major GC的策略选择过程)。Major GC的速度一般会比Minor GC慢10倍以上。
  3. Full GC:一般根据语义来定义内存区域,对Full GC的定义也不同,有时候指老年代的垃圾回收,有时候指全堆(新生代+老年代)的垃圾回收,还可能指有用户线程暂停(Stop-The-World)的垃圾回收(如GC日志中)。一般都存在老年代GC。

5.垃圾回收过程:

  1. 用户线程创建的对象优先分配在Eden区,当Eden区空间不够时,会触发Minor GC。

    Minor GC步骤:
    (1) 复制存活对象到Suvivor区另一块——>存活对象年龄+1
    (2)清空Eden区和前一块Survivor区
    (3)给需要创建的对象分配内存
    异常情况:如果留空的S区空间不足存放GC后存活对象时,所有存活对象,通过分配担保机制,进入老年代。
  2. 垃圾回收结束后,用户线程又开始新创建对象并分配在Eden区,当Eden区空间不足时,重复上次
    的步骤进行Minor GC。
  3. 年老对象晋升到老年代
    既然虚拟机采用分代收集的思想来管理内存,那么内存回收时就必须能识别哪些对象应该放在新生代,哪些对象应该放在老年代中。
    为了做到这点,虚拟机给每个对象定义了一个对象年龄(Age)计数器。如果对象在Eden出生并经过一次Minor GC后仍然存活,并且能被Survivor容纳的话,将被移动到Survivor空间中,并且把对象年龄设为1。对象在Survivor空间中每"熬过"一次Minor GC,年龄就增加1岁,当它的年龄增加到一定程度(默认为15岁),就将晋 升到老年代中。
  4. Survivor空间不足,存活对象通过分配担保机制进入老年代。

6.垃圾回收算法

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

此算法类似于类似本地文件夹内,先将要删除的文件标记- -下,之后遍历一个一个的删除。
分为两个阶段:标记、清除。
老年代的回收算法。
不足:效率不高,产生大量不完整的内存碎片(导致:在进入大对象,如果没有连续空间存放,触发Major GC)。

(2)复制算法(Copying算法)

此算法类似本地文件夹内,将要删除的文件全部复制到另一个文件夹,之后把前一个文件夹全删了。
新生代的回收算法。
内存使用率不高(50%)。
优点:实现简单、运行高效、不存在内存碎片问题。

(3)标记-整理算法(Mark-Compact算法)

老年代的回收算法。
两个阶段:标记、整理(移动存活对象到一端内存,清理另一端内存)。

(4)分代收集算法

在新生代中,每次垃圾回收都有大批对象死去,只有少量存活,因此我们采用复制算法;而老年代中对象存活率高、没有额外空间对它进行分配担保,就必须采用"标记-清理"或者"标记-整理"算法。

7.STW (Stop The World):GC导致的暂停用户线程

(1) 原因:用户线程和GC线程并发、并行的执行,标记可回收的对象,在用户线程并发执行时,可能重新有引用指向该对象。
(2) GC时,什么情况会STW
新生代GC:都会STW
影响:因为Minor GC时间非常快,几乎忽略不计,影响很小
老年代GC:根据阶段来看是否会STW
影响: 非常大。(老年代空间大, 需要回收的对象多,耗时也多)
Full GC一般是指影响很大(STW), 所以一般都包含Major GC。可能出现Minor GC

二、垃圾收集器

java中会触发gc的方法 java gc触发时机_老年代_04


并行(Parallel) : 指多条垃圾收集线程并行工作,用户线程仍处于等待状态。

并发(Concurrent) : 指用户线程与垃圾收集线程同时执行(不一定并行,可能会交替执行),用户程序继续运 行,而垃圾收集程序在另外一个CPU上。

1.新生代收集器

1.Serial(串行GC)

特性:单线程、STW、复制算法

2.ParNew(并行GC)

特性:多线程、STW、复制算法
和CMS搭配使用在用户体验优先的程序中。用户要调用程序接口,执行程序代码

3.Parallel Scanvenge(并行GC)

特性
(1) 多线程、STW.复制算法
(2)吞吐量优先:主要是后台任务型的程序(比如定时任务,不涉及用户使用的程序)
(3)自适应的调节策略: JVM设置这个参数=true之后, JVM可以监控性能,并动态的设置内存相关参数(如年龄阈值、新生代大小、Eden和S区比例)

2.老年代收集器

1.Serial Old收集器(串行GC)

特性:单线程、标记整理算法
CMS在发生并发失败 (Concurrent Mode Failure)时作为备用垃圾回收方案

2.Parallel Old收集器(并行GC)

特性
(1) 多线程、标记整理算法、STW
(2)吞吐量优先一搭配Parallel Scanvenge一起使用

3.CMS收集器(并发GC)

特性

(1)并发收集、低停顿

(2)“标记-清除”算法

(3)分为4个阶段:

<1>初始标记(CMS initial mark): 初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快, 需要“Stop The World”。

<2>并发标记(CMS concurrent mark) :并发标记阶段就是进行GC Roots Tracing的过程。

<3>重新标记(CMS remark) :重新标记阶段是为了修正并发标记期间因用户程序继续运作而导致标记产生 变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标 记的时间短,仍然需要“Stop The World”。

<4>并发清除(CMS concurrent sweep) :并发清除阶段会清除对象。

四个阶段中: .

(1) <1>和<3>执行速度快,消耗时间少一暂停用户线程时间少

(2) <2>和<4>执行时间相对较慢,但是可以和用户线程并发执行

总体来看,CMS垃圾回收的工作是和用户线程同时执行,此为CMS名称的由来。

缺陷

1.CMS垃圾回收线程会抢占CPU资源,导致用户线程总的执行时间更少。

2.浮动垃圾问题:

(1)产生原因: CMS第四个阶段,用户线程并发执行又可能导致有对象进入老年代,而老年代也可能剩余空间不足,触发Major GC,就会出现Concurrent Mode Failure。

(2)解决方案:使用Serial Old来进行垃圾回收。

(3)标记清除算法会导致老年代空间碎片,如果进入的对象没有连续的可用空间,触发Full GC。

图中的E表示该region属于Eden内存区域,S表示属于Survivor内存区域,T表示属于Tenured内存区域。图中空白的表示未使用的内存空间。G1垃圾收集器还增加了一种新的内存区域,叫做Humongous内存区域,如图中的H块。这种内存区域主要用于存储大对象-即大小超过一个region大小的50%的对象。

java中会触发gc的方法 java gc触发时机_老年代_05


java中会触发gc的方法 java gc触发时机_CMS_06


可能出现的情况:(上图)

(1)2,6不一定清除掉。

(2)创建对象时,导致有对象进入老年代。

(3)老年代有可能空间不足分配进入老年代对象的内存。

4.G1收集器(全区域的垃圾回收器)

(1)整体看基于标记整理算法,局部看基于复制算法

(2)用户体验优先

(3)内存划分:堆内存划分为很多region,每个region都是动态指定为Eden区、 Survivor区、Tenured区(老年代内存)。

新生代垃圾收集:

在G1垃圾收集器中,年轻代的垃圾回收过程使用复制算法。把Eden区和Survivor区的对象复制到新的Survivor区域。

java中会触发gc的方法 java gc触发时机_老年代_07


老年代垃圾收集:

对于老年代上的垃圾收集,G1垃圾收集器也分为4个阶段,基本跟CMS垃圾收集器一样,但略有不同:

(1)初始标记:可以和Minor GC (新生代GC)同时执行,STW

(2)并发标记:Garbage First,清理老年代总(T区、 Tenured Generation) , 存活率很小或没有对象存活的T区。

(3)最终标记:STW,和CMS第三个阶段算法不同。

(4)筛选回收:因为和CMS算法不同,采取clean up/copy和新生代类似的整理工作。可以和Minor GC (新生代GC)同时执行, 需要STW。

java中会触发gc的方法 java gc触发时机_CMS_08


针对用户体验优先:(1)ParNew+CMS;(2)G1

针对吞吐量优先:Parallel Scanvenge+Parallel Old

三、垃圾回收的时机

1.Minor GC触发条件

创建对象在Eden区,且Eden区空间不足

2.Majar GC触发的条件

在对象需要存放在老年代,而老年代空间不足,都会触发,包括:
(1)新生代年老对象晋升
(2)大对象直接进入
(3)Minor GC的分配担保机制,在发生Minor GC之前,如果老年代最大可用的连续空间小于新生代所有对象的总空间,以下情况将会触发Major GC:

  1. 不允许空间分配担保
  2. 允许空间分配担保,但老年代最大可用连续空间小于历次晋升到老年代的对象的平均大小
  3. 允许空间分配担保,但在执行Minor GC后老年代空间不足CMS无法处理浮动垃圾,可能会出现“Concurrent Mode Failure”而导致另一次Full GC。