JAVA从入门到精通-垃圾回收机制 以及它的触发
孔庆琦 2018-04-02 来源 : 阅读 2297 评论 0

摘要:学习JAVA从入门到精通的垃圾回收机制,Full GC定义是相对明确的,就是针对整个新生代、老生代、元空间(metaspace,java8以上版本取代perm gen)的全局范围的G,了解这些对JAVA从入门到精通的路上起到很大的作用。

1. Full GC定义是相对明确的,就是针对整个新生代、老生代、元空间(metaspace,java8以上版本取代perm gen)的全局范围的GC;

2. Minor GC和Major GC是俗称,在Hotspot JVM实现的Serial GC, Parallel GC, CMS, G1 GC中大致可以对应到某个Young GC和Old GC算法组合;

3. 最重要是搞明白上述Hotspot JVM实现中几种GC算法组合到底包含了什么。

3.1 Serial GC算法:Serial Young GC + Serial Old GC (敲黑板!敲黑板!敲黑板!实际上它是全局范围的Full GC);

3.2 Parallel GC算法:Parallel Young GC + 非并行的PS MarkSweep GC / 并行的Parallel Old GC(敲黑板!敲黑板!敲黑板!这俩实际上也是全局范围的Full GC),选PS MarkSweep GC 还是 Parallel Old GC 由参数UseParallelOldGC来控制;

3.3 CMS算法:ParNew(Young)GC + CMS(Old)GC (piggyback on ParNew的结果/老生代存活下来的object只做记录,不做compaction)+ Full GC for CMS算法(应对核心的CMS GC某些时候的不赶趟,开销很大);

3.4 G1 GC:Young GC + mixed GC(新生代,再加上部分老生代)+ Full GC for G1 GC算法(应对G1 GC算法某些时候的不赶趟,开销很大);

4. 搞清楚了上面这些组合,我们再来看看各类GC算法的触发条件。

简单说,触发条件就是某GC算法对应区域满了,或是预测快满了。比如,

4.1 各种Young GC的触发原因都是eden区满了;

4.2 Serial Old GC/PS MarkSweep GC/Parallel Old GC的触发则是在要执行Young GC时候预测其promote的object的总size超过老生代剩余size;

4.3 CMS GC的initial marking的触发条件是老生代使用比率超过某值;

4.4 G1 GC的initial marking的触发条件是Heap使用比率超过某值,跟4.3 heuristics 类似;

4.5 Full GC for CMS算法和Full GC for G1 GC算法的触发原因很明显,就是4.3 和 4.4 的fancy算法不赶趟了,只能全局范围大搞一次GC了(相信我,这很慢!这很慢!这很慢!);

5 题主说的 “Full GC会先触发一次Minor GC” - 指的应该是

5.1 (说错了,我删了)

5.2 PS MarkSweep GC/Parallel Old GC(Full GC)之前会跑一次Parallel Young GC;

原因就是减轻Full GC 的负担。

5.2 -> ps

当准备要触发一次young GC时,如果发现统计数据说之前young GC的平均晋升大小比目前old gen剩余的空间大,则不会触发young GC而是转为触发full GC(因为HotSpot VM的GC里,除了CMS的concurrent collection之外,其它能收集old gen的GC都会同时收集整个GC堆,包括young gen,所以不需要事先触发一次单独的young GC);或者,如果有perm gen的话,要在perm gen分配空间但已经没有足够空间时,也要触发一次full GC;或者System.gc()、heap dump带GC,默认也是触发full GC。

重点提一下 cms gc 的重要参数

cms

-XX:CMSInitiatingOccupancyFraction=80  设置cms cycle trigger 的阈值 默认-1 <占用 老年带的大小>
-XX:+UseCMSInitiatingOccupancyOnly
g1
-XX:InitiatingHeapOccupancyPercent=80  设置concurrent GC cycle trigger <默认 45% ,占用整个heap的大小>


jvm hotspot中包含的所有的垃圾回收器   串行 并行 并发 g1
连线的表示可以搭配使用
●并行(Parallel):  指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。
●并发(Concurrent):指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),用户程序在继续运行,而垃圾收集程序运行于另一个CPU上。
新生代
1. Serial收集器 <单线程> [串行]
2. ParNew收集器 (serial 的多线程版本) [并行]
3. Parallel Scavenge收集器<复制算法, 并行多线程收集器> [并行]
老年代
1. Serial Old收集器 <serial 收集器的老年代版本>  [串行]
2. Parallel Old收集器 <Parallel Scavenge收集器的老年代版本, 标记-整理> [并行]
3. CMS <获取最短回收停顿时间为目标的收集器,  标记—清除>   [并发]
ps: 5个过程  2个stw
1. 初始标记(stw) 
2. 并发标记 
3. 并发预清理
4. <最终标记>重标记(stw) 
5. 并发清理 
6. 重置  
g1 垃圾回收器
G1提供了两种GC模式,Young GC和Mixed GC,两种都是Stop The World(STW)

我所在公司g1 垃圾收集器的gclog

{Heap before GC invocations=3573 (full 90):
garbage-first heap total 4538368K, used 3325904K [0x00000006ab000000, 0x00000006ac0008a8, 0x00000007c0000000)
region size 16384K, 172 young (2818048K), 9 survivors (147456K)
Metaspace used 163630K, capacity 188987K, committed 192256K, reserved 1220608K
class space used 16357K, capacity 20273K, committed 20992K, reserved 1048576K
2018-03-25T00:25:58.605+0800: 224650.575: [GC pause (G1 Evacuation Pause) (young)
Desired survivor size 184549376 bytes, new threshold 15 (max 15)
- age 1: 17013632 bytes, 17013632 total
- age 2: 13209056 bytes, 30222688 total
- age 3: 14502912 bytes, 44725600 total
- age 4: 15785216 bytes, 60510816 total
- age 5: 14071128 bytes, 74581944 total
- age 6: 13162464 bytes, 87744408 total
- age 7: 12541320 bytes, 100285728 total
224650.575: [G1Ergonomics (CSet Construction) start choosing CSet, _pending_cards: 23840, predicted base time: 24.30 ms, remaining time: 175.70 ms, target pause time: 200.00 ms]
224650.575: [G1Ergonomics (CSet Construction) add young regions to CSet, eden: 163 regions, survivors: 9 regions, predicted young region time: 36.08 ms]
224650.575: [G1Ergonomics (CSet Construction) finish choosing CSet, eden: 163 regions, survivors: 9 regions, old: 0 regions, predicted pause time: 60.38 ms, target pause time: 200.00 ms]
, 0.0731631 secs]
[Parallel Time: 68.3 ms, GC Workers: 4]
[GC Worker Start (ms): Min: 224650575.6, Avg: 224650575.6, Max: 224650575.6, Diff: 0.1]
[Ext Root Scanning (ms): Min: 2.9, Avg: 3.2, Max: 3.8, Diff: 0.9, Sum: 13.0]
[Update RS (ms): Min: 8.7, Avg: 8.9, Max: 9.0, Diff: 0.3, Sum: 35.5]
[Processed Buffers: Min: 43, Avg: 54.2, Max: 62, Diff: 19, Sum: 217]
[Scan RS (ms): Min: 0.0, Avg: 0.0, Max: 0.1, Diff: 0.0, Sum: 0.2]
[Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.1, Diff: 0.1, Sum: 0.1]
[Object Copy (ms): Min: 55.6, Avg: 55.9, Max: 56.1, Diff: 0.6, Sum: 223.5]
[Termination (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
[Termination Attempts: Min: 1, Avg: 1.0, Max: 1, Diff: 0, Sum: 4]
[GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.1]
[GC Worker Total (ms): Min: 68.1, Avg: 68.1, Max: 68.1, Diff: 0.1, Sum: 272.5]
[GC Worker End (ms): Min: 224650643.7, Avg: 224650643.7, Max: 224650643.7, Diff: 0.0]
[Code Root Fixup: 0.3 ms]
[Code Root Purge: 0.0 ms]
[Clear CT: 0.3 ms]
[Other: 4.3 ms]
[Choose CSet: 0.0 ms]
[Ref Proc: 3.1 ms]
[Ref Enq: 0.1 ms]
[Redirty Cards: 0.4 ms]
[Humongous Register: 0.0 ms]
[Humongous Reclaim: 0.0 ms]
[Free CSet: 0.2 ms]
[Eden: 2608.0M(2608.0M)->0.0B(2592.0M) Survivors: 144.0M->160.0M Heap: 3248.0M(4432.0M)->664.0M(4432.0M)]
Heap after GC invocations=3574 (full 90):
garbage-first heap total 4538368K, used 679888K [0x00000006ab000000, 0x00000006ac0008a8, 0x00000007c0000000)
region size 16384K, 10 young (163840K), 10 survivors (163840K)
Metaspace used 163630K, capacity 188987K, committed 192256K, reserved 1220608K
class space used 16357K, capacity 20273K, committed 20992K, reserved 1048576K
}
[Times: user=0.28 sys=0.00, real=0.07 secs]
mixed GC


   1. 全局并发标记(global concurrent marking)
   2. 拷贝存活对象(evacuation)
自己的理解 <g1>
1. gc 会对eden 和 surivor 重新分配   回收内存 提高内存利用率  region [1-32m] 代码写死的最大2048个region
2. target pause time: 200ms  这个是g1 的默认配置  [-XX:MaxGCPauseMillis=time]
3. gc 可以对垃圾回收进行预测
4. ygc 和 mixgc 都是会stw
5. 尽量避免fullgc 产生 <某些情况下 这会导致Serial gc,很慢 很慢>

6. 整个内存分为 E V H<巨型区域,放大对象的> O 

以下g1 触发gc的条件转自: //blog.jobbole.com/109170/

触发Full GC

在某些情况下,G1触发了Full GC,这时G1会退化使用Serial收集器来完成垃圾的清理工作,它仅仅使用单线程来完成GC工作,GC暂停时间将达到秒级别的。整个应用处于假死状态,不能处理任何请求,我们的程序当然不希望看到这些。那么发生Full GC的情况有哪些呢?

· 并发模式失败

G1启动标记周期,但在Mix GC之前,老年代就被填满,这时候G1会放弃标记周期。这种情形下,需要增加堆大小,或者调整周期(例如增加线程数-XX:ConcGCThreads等)。

· 晋升失败或者疏散失败

G1在进行GC的时候没有足够的内存供存活对象或晋升对象使用,由此触发了Full GC。可以在日志中看到(to-space exhausted)或者(to-space overflow)。解决这种问题的方式是:

a,增加 -XX:G1ReservePercent 选项的值(并相应增加总的堆大小),为“目标空间”增加预留内存量。

b,通过减少 -XX:InitiatingHeapOccupancyPercent 提前启动标记周期。

c,也可以通过增加 -XX:ConcGCThreads 选项的值来增加并行标记线程的数目。

· 巨型对象分配失败

当巨型对象找不到合适的空间进行分配时,就会启动Full GC,来释放空间。这种情况下,应该避免分配大量的巨型对象,增加内存或者增大-XX:G1HeapRegionSize,使巨型对象不再是巨型对象。

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标编程语言JAVA频道!

本文由 @职坐标 发布于职坐标。未经许可,禁止转载。
喜欢 | 2 不喜欢 | 0
看完这篇文章有何感觉?已经有2人表态,100%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论
本文作者 联系TA

对MVC模式和三层架构有深入的研究

  • 10
    文章
  • 6086
    人气
  • 92%
    受欢迎度

已有24人表明态度,92%喜欢该老师!

进入TA的空间
求职秘籍 直通车
  • 索取资料 索取资料 索取资料
  • 答疑解惑 答疑解惑 答疑解惑
  • 技术交流 技术交流 技术交流
  • 职业测评 职业测评 职业测评
  • 面试技巧 面试技巧 面试技巧
  • 高薪秘笈 高薪秘笈 高薪秘笈
TA的其他文章 更多>>
JAVA从入门到精通-CoreJava读书笔记--对象与类(一)
经验技巧 100% 的用户喜欢
JAVA语言-代码块,静态代码块,内部类,静态内部类的加载时机
经验技巧 67% 的用户喜欢
JAVA语言-多线程实现的四种方式
经验技巧 100% 的用户喜欢
JAVA语言-AVA文件流
经验技巧 100% 的用户喜欢
JAVA从入门到精通-final和static
经验技巧 100% 的用户喜欢
其他海同师资 更多>>
吕益平
吕益平 联系TA
熟悉企业软件开发的产品设计及开发
周鸣君
周鸣君 联系TA
擅长Hadoop/Spark大数据技术
范佺菁
范佺菁 联系TA
擅长Java语言,只有合理的安排和管理时间你才能做得更多,行得更远!
金延鑫
金延鑫 联系TA
擅长与学生或家长及时有效沟通
程光淼
程光淼 联系TA
精通C、C++等语言、智能芯片开发
经验技巧30天热搜词 更多>>

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程