GC浅谈(二)

最糟糕的是人们在生活中经常受到错误志向的阻碍而不自知,真到摆脱了那些阻碍时才能明白过来。 —— 歌德

1. 对象的标记过程

1.1 快速枚举GC Roots

在可达性分析过程中,为了准确找出与GC Roots相关联的对象,必须要求整个执行系统看起来像是被冻结在某个时间点上,即暂停所有运行中的线程,不可以出现对象的引用关系还在不断变化的情况,这点是导致GC时必须停顿所有线程(“Stop the world”)的一个重要原因。
  可作为GC Roots的节点主要在全局性的引用(例如常量或静态类属性)与执行上下文(本地变量表中的引用)中。
  在HosSpots中,是使用一组称为OopMap的数据结构来存放着对象的引用。类加载完成时,HotSpot把对象内什么偏移量上是什么类型的数据计算出来存储到OopMap中,通过JIT编译出来的本地代码,也会记录下栈和寄存器中哪些位置是引用。通过扫描OopMap的数据就可以快速标识出存活的对象。

1.2 安全的进行GC

在发生GC时,JVM通过安全点和安全区域来保证GC可以安全的进行。

1.2.1 安全点

线程运行时,只有在到达安全点(Safe Point)才能停顿下来进行GC。
  基于OopMap数据结构,HotSpot可以快速完成GC Roots的遍历,不过HotSpot并不会为每条指令都生成对应的OopMap,只会在Safe Point处记录这些信息。
  当发生GC时,不直接对线程进行中断操作,而是简单的设置一个中断标志,每个线程运行到Safe Point的时候,主动去轮询这个中断标志,如果中断标志为真,则将自己进行中断挂起。

1.2.2 安全区域

处于Sleep或Blocked状态的线程在GC时无法响应JVM的中断请求,无法到Safe Point去中断挂起,对于这种情况,可以使用安全区域(Safe Region)来解决。
  Safe Region是指在一段代码片段中,对象的引用关系不会发生变化,在这个区域中的任何位置开始GC都是安全的。

  • 当线程运行到Safe Region的代码时,首先标识已经进入了Safe Region,如果这段时间内发生GC,JVM会忽略标识为Safe Region状态的线程。
  • 当线程即将离开Safe Region时,会检查JVM是否已经完成GC,如果完成了,则继续运行,否则线程必须等待直到收到可以安全离开Safe Region的信号为止。

2. 垃圾收集器

垃圾收集器是内存回收的具体实现,JAVA虚拟机没有规定垃圾收集器该如何实现,且提供参数供用户根据自己的要求将垃圾收集器进行组合使用。



  上图展示了7种不同的分代收集器,若两个收集器直接存在连线,则说明可以组合使用。虚拟机所处的区域,则表示是属于新生代收集器还是老年代收集器。

2.1 Serial收集器(新生代串行收集器)

串行收集器主要有两个特点:第一,仅使用单线程进行垃圾回收;第二,它是独占式的垃圾回收。
  之所以是独占式的,是因为在串行收集器运行时,应用程序的所有线程都停止工作,进行等待。
  虽然如此,串行收集器却是一个极为高效的收集器,使用的是复制算法,实现相对简单,且没有线程的切换开销。
  使用-XX:+UseSerialGC参数可以指定使用新生代串行收集器和老年代串行收集器。当JVM在Client模式下,Serial收集器是默认的垃圾收集器。

Serial收集器工作示意图

2.2 ParNew收集器(并行收集器)

并行收集器工作在新生代,只是简单的将串行收集器多线程化,回收策略、算法以及参数和串行收集器是一样的。并行收集器也是独占式的,在GC过程中,应用程序也会全部暂停,由于使用多线程进行垃圾回收,因此产生的停顿时间要短于串行收集器。
  开启并行收集器可以使用以下参数:
  (1) -XX:UseParNewGC: 新生代使用并行收集器,老年代使用串行收集器。
  (2) -XX:UseConcMarkSweepGC: 新生代使用并行收集器,老年代使用CMS。
  并行收集器GC时的线程数量可以使用-XX:ParallelGCThreads参数指定。

并行收集器工作示意图

2.3 新生代并行回收(Parallel Scavenge)收集器

Parallel Scavenge收集器是一个采用多线程基于复制算法并工作在新生代的收集器,其中一个特点是它比较关注系统的吞吐量。
  吞吐量 = 用户代码运行时间 /(用户代码运行时间 + 垃圾收集时间)
  使用以下参数可以开启Parallel Scavenge:
  (1) -XX:+UseParallelGC: 新生代使用Parallel Scavenge,老年代使用串行收集器。
  (2) -XX:+UseParallelOldGC: 新生代和老年代都使用并行回收收集器。
  Parallel Scavenge提供了两个参数用于精确控制吞吐量:
  1、-XX:MaxGCPauseMillis 设置垃圾收集的最大停顿时间。
  2、-XX:GCTimeRatio 设置吞吐量大小。
  除此之外,Parallel Scavenge还支持自适应的GC调节策略,使用-XX:UseAdaptiveSizePolicy可以打开自适应的GC调节策略。在这种模式下,新生代的大小,eden和survivor的比例,晋升老年代的对象年龄等参数会被自动调整,以达到系统运行的最优化。

Parallel Scavenge收集器工作示意图

2.4 Serial Old收集器

Serial Old 是一个采用单线程基于标记-整理算法并工作在老年代的收集器,是Client模式下老年代默认的收集器。

Serial Old收集器工作示意图

2.5 Parallel Old收集器(并行GC)

Parallel Old是一个采用多线程基于标记-整理算法并工作在老年代的收集器。同样也是一个关注系统吞吐量的收集器。


Parallel Old收集器工作示意图

2.6 CMS收集器

CMS主要关注系统的停顿时间,使用的是标记-清除算法,工作在老年代,GC时,分为以下四个阶段:
  (1) 初始标记:这个过程只是标记需要回收的对象,这个阶段仍然会Stop The World。
  (2) 并发标记:进行GC Roots Tracing的过程,可以和用户线程一起工作。
  (3) 重新标记:用于修正并发标记期间由于用户程序继续运行而导致标记产生变动的那部分记录,这个过程也会Stop The World。
  (4) 并发清除:多个线程并行进行垃圾回收,可以和用户线程一起工作。


CMS收集器工作示意图

  CMS收集器的缺点:
  (1) 对CPU资源比较敏感,在并发阶段,虽然不会导致用户线程停顿,但是会占用一部分线程资源,降低系统的总吞吐量。
  (2) 无法处理浮动垃圾,在并发清理阶段,用户线程的运行依然会产生新的垃圾对象,这部分垃圾只能在下一次GC时收集。
  (3) CMS是基于标记-清除算法实现的,意味着收集结束后会造成大量的内存碎片,可能导致出现老年代剩余空间很大,却无法找到足够大的连续空间分配当前对象,不得不提前触发一次Full GC。

2.7 G1收集器

G1(Garbage First)是JDK1.7提供的一个工作在新生代和老年代的收集器,基于“标记-整理”算法实现,在收集结束后可以避免内存碎片问题。
  G1收集器有以下优点:
  (1) 并行与并发:充分利用多CPU、多核来缩短Stop the world停顿时间。
  (2) 分代收集:不需要其他收集器配合就可以管理整个Java堆,采用不同的方式处理新建的对象、已经存活一段时间和经历过多次GC的对象获取更好的收集效果。
  (3) 空间整合:G1在运行期间不会产生内存空间碎片,有利于应用的长时间运行,且分配大对象时,不会导致由于无法申请到足够大的连续内存而提前触发一次Full GC。
  (4) 可预测的停顿:G1中可以建立可预测的停顿时间模型,能让使用者明确指定在M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒。
  使用G1收集器时,Java堆的内存布局与其他收集器有很大区别,它将整个Java堆划分为多个大小相等的独立区域(Region),新生代和老年代不再试物理隔离了,都是一部分Region(不需要连续)的集合。G1跟踪各个Region里的垃圾堆积的大小,在后台维护一个优先列表,根据允许的收集时间,优先回收价值最大的Region,避免在整个Java堆上进行全区域的垃圾回收,确保了G1收集器可以在有限的时间内尽可能收集更多的垃圾。
  在G1收集器中,Region之间的对象引用以及其他收集器中的新生代和老年代之间的对象引用,JVM都是使用Remembered Set数据结构来存储,以避免全堆扫描。G1中每个Region都有一个对应的Remenbered Set,当虚拟机发现程序对Reference类型的数据进行写操作时,会产生一个Write Barrier暂时中断写操作,检查Reference引用的对象是否处于相同的Region中,如果不是,则通过CardTable把相关引用信息记录到被引用对象所属Region的Remenbered Set中。
  G1收集器GC时,主要分为以下四个阶段:
  (1) 初始标记:标记与GC Roots直接相关联的对象,该阶段会Stop the world。
  (2)并发标记:从 GC Roots开始对堆中的对象进行可达性分析,找出存活对象,可与应用线程并发执行。
  (3)最终标记:为了修正在并发标记期间因用户线程执行导致标记产生变化的那一部分标记记录。
  (4)筛选回收:对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划。

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

推荐阅读更多精彩内容