[JVM入门指南02]GC垃圾回收机制

概述

在JVM中主要的结构为:虚拟机栈、堆、方法区。其中虚拟机栈的栈帧在编译器就已经确定大小的,随着方法的结束或线程的技术,虚拟机栈的内存也随着回收。而Java堆和方法区这两个区域则有很显著的不确定性,这部分内存的分配和回收都是动态的,GC所关注的真是这部分内存该如何管理。

本篇文章就以下三方面GC所要完成的三件事:

  • 哪些内存需要回收?(对象存活算法)
  • 什么时候回收?(触发GC的条件)
  • 如何回收?(GC的工作原理)

哪些内存需要回收

如何判定哪些对象需要回收?在堆里面存放了几乎所有的对象实例,在GC之前第一件事就是要确定这些对象哪些还“存活”着,哪些已经“死去”。其中判断对象是否存活有两种算法:可达性分析算法、引用计数算法。

可达性分析算法

通过一系列的“GC Roots”根对象作为始节点,开始往下遍历有引用关系的对象形成一条“引用链”,通过这条引用链的可达的对象是存活的,不可达的对象则是不再使用。

那么什么样的对象可以GC Roots呢?主要是以下对象:

  1. 虚拟机栈中的引用对象
  2. 方法区的类静态的引用对象、常量的引用对象
  3. Java虚拟机内部引用:基本数据类型的Class对象、异常对象、系统类加载器
  4. 所有同步锁持有的对象
  5. 反映虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存。

可达性分析算法是大多数系统使用的对象存活判断算法。

引用计数算法

在对象中添加一个引用计数器,每当有一个地方引用它,计数器就+1,当一个引用失效,计数器就-1,当计数器>0时就表示对象为存活使用状态,不得回收。大多数不会用这个办法来判断对象存活,因为当对象实例相互引用时,当栈中的引用已经失效,对象也还是不能回收。


上面的可达性分析算法和引用计数算法都用到了引用,这种引用默认是强引用。在JDK1.2版本之后,Java除了有强引用外,还增加了三种引用:

  • 软引用(SoftReference): 内存溢出前,可对持有该引用的对象回收
  • 弱引用(WeakReference):GC就会被回收,相当于没有引用。
  • 虚引用(PhantomReference): 无法通过其获得对象实例,唯一目的是当对象被回收时能收到一个系统通知。

如果对象被可达性分析算法引用计数算法识别为无使用对象就可以被GC回收吗?不是,一个对象要至少要经过两个的标志过程。其还会查询对象是否重写了finalize()方法,如果重写了就会用另一个Finalize线程去执行这个finalize方法,这个方法可以回收时使对象重新被引用,但官方并不推荐这样做。


堆中的对象实例可以使用可达性分析算法和引用计数算法来决定是否回收。但方法区的常量池和类型信息是否回收却另有条件:

  • 常量池的字符串和符号引用
    虚拟机中没有任何对象有引用到它。

  • 类型卸载
    1.该类的所有实例被回收
    2.该类的ClassLoader被回收
    3.Class对象没有被任何地方引用
    以上三种条件同时被满足。

什么时候回收

根据两个分代假说:绝大多数的对象都是朝生夕死熬过越多次的GC回收的对象就越难回收。把堆进行了分代:新生代(Eden、From、To)、老年代,在GC时也进行了分代回收。

分代回收和收集算法

Minor GC: 回收新生代的无使用对象,新生代的对象的特性是大多数是朝生夕死的。触发时机有:

  • Eden区空间不足,触发Minor GC
    由于Eden空间大小有限,所以Minor GC触发的更加频繁,这就需要收集算法速度快、效率高,一般使用标记-复制算法对这一区域进行回收(后面讲)。

Major GC:回收老年代的无使用对象。一般使用标记-清除算法标记-整理算法进行回收。

Full GC: 回收堆和方法区的无使用对象。Full GC回收范围比较大,执行的时间较长可能会造成卡顿,所以要尽量减少Full GC的次数。触发时机大致有:

  • 老年代的空间不足
    由新生代对象的进入老年代、大对象直接进入老年代等,如果在老年代的最大连续空间上无法存放这些对象时,就会进行一次Full GC回收。

  • 方法区的空间不足
    方法区主要存储类型信息和常量池,也有空间不足的风险,会进行Full GC回收

  • System.gc()被显示调用会Full GC回收

三种垃圾收集算法:

1. 标记-清除算法

原理:用可达性分析算法将不可用的对象进行标记,然后对无用的对象进行清除
缺点:在对象很多的情况下,标记的效率低。清除对象之后会产生内存碎片,内存不连续。
作用:在老年代回收中一些收集器会使用此算法

2. 标记-复制算法

原理:将内存空间一分为二,一半用于对象的存放,一半空闲。如果存放对象的区域满了,使用可达性分析算法把存活的对象移动标记出来,然后复制到另一个空的区域,同时把之前的区域全部清空变成空的连续空间。
缺点:如果存活对象很多,要产品大量的内存复制开辟。内存空间只能用一半优点浪费资源。
作用:在新生代朝生夕死的对象中一般用此回收算法。但新生代中对复制算法进行了优化,但这种算法加入了分配担保机制防止存活对象过多分配不了的情况。使用了一种Appel式的回收算法:

Appel回收

3. 标记-整理算法

原理:标记的过程跟标记-清除算法一样,然后整理存活的对象往一端移动,然后存活边界之外的对象全部清除
缺点:移动对象有一定的风险。对象太多效率不高
作用:主要作用在老年代。

标记-整理算法

如何回收

GC使用的垃圾收集器进行回收,随着不断的发展,垃圾收集器也越来越多,这里列举常规的垃圾收集器并进行分为三类:单线程收集器、多线程收集器、并发收集器。

单线程收集器

单线程的收集器的组合有:Serial/Serial Old收集器。它们不仅仅用一个收集线程去完成收集操作,而且在收集线程工作的时候,用户线程必须停止等待,直到收集完成为止。如图是Serial/Serial Old收集器示意图:

Serial/Serial Old收集器

如果客户端的内存资源受限,处理器核心数较少或单核处理器来说,其简单高效的可以使收集器最快的工作完。

多线程并行收集器

多线程的收集器有:ParNew、Parallel Scavenge、Parallel Old,其中Parallel Scavenge/Parallel Old为组合收集器。这些多线程收集器仅仅是增加了垃圾收集线程,用户线程依然是停止等待垃圾收集的。

Parallel Scavenge/Parallel Old组合收集器

parNew收集器:其实就是Serial的多线程版本,目前能与Serial收集器和CMS收集器合作。

Parallel Scavenge收集器:一般配合Parallel Old收集器使用。相比于parNew收集器,它更加注重是吞吐量的控制,吞吐量就是用户线程执行的时间占总CPU运行的时间,吞吐量当然是越大越好。

多线程一般用服务端,因为多线程的执行,有时间片轮转的消费时间,如果对于单处理器来说无疑处理效率更慢。但对于资源很好,不用与用户交互的分析运算的服务端却可以增加执行效率。

并发收集器

并发收集器有:CMS收集器,是一款以系统停顿的时间尽量较短,用户体验较好为目标的收集器。它的收集线程可以与用户线程并发执行。CMS有三次的标记(初始标记、并发标记、重新标记)和一次清理(并发清理),在三次的标记中有两次标记需要较短用户线程停止,一次较长的与用户线程并发的标记,和与用户线程并发的清除。

CMS收集器

初始标记:标记GC Roots关联的第一个对象,时间很短
并发标记:和用户线程并发执行GC Roots的引用链(可达性分析算法),时间较长
重新标记:重新查找在并发标记阶段,用户线程运行生成的新的引用链。时间比初始标记长一点。
并发清除:用标记-清除算法把无用对象进行清除。

三大缺点:一:CPU敏感,并发对核心数少的处理器对用户线程的运行可能会造成影响。二:浮动垃圾:在并发清理阶段产生的垃圾只能等下一次GC回收。三:内存碎片,标记-清理法会产品大量的不连续的内存空间。

小结

本文从那些内存需要回收什么时候回收如何回收作为执行分别写出了两个对象存活判断算法、Class区回收的条件、回收的分代机制与收集时机、三个收集算法和常用的垃圾收集器。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容