转自CSDN

上一篇总结GC的基础算法,各种GC收集器的基本原理,还是比较粗粒度的概念。这篇会整理一些GC的常见概念,理解了这些概念,相信对GC有更加深入的理解

1. 什么时候会触发Minor GC?

  • Eden区域满了,或者新创建的对象大小 > Eden所剩空间
  • CMS设置了CMSScavengeBeforeRemark参数,这样在CMS的Remark之前会先做一次Minor GC来清理新生代,加速之后的Remark的速度。这样整体的stop-the world时间反而断
  • Full GC的时候会先触发Minor GC

2. 什么时候会触发Full GC?

  • Minor GC后存活的对象晋升到老年代时由于悲观策略的原因,有两种情况会触发Full GC, 1种是之前每次晋升的对象的平均大小 > 老年代剩余空间
  • 1种是Minor GC后存活的对象超过了老年代剩余空间。这两种情况都是因为老年代会为新生代对象的晋升提供担保,而每次晋升的对象的大小是无法预测的,所以只能基于统计,1个是基于历史平均水平,一个是基于下一次可能要晋升的最大水平。这两种情况都是属于promotion failure
  • CMS失败,发生concurrent mode failure会引起Full GC,这种情况下会使用Serial Old收集器,是单线程的,对GC的影响很大。concurrent mode failure产生的原因是老年代剩余的空间不够,导致了和gc线程并发执行的用户线程创建的大对象(由PretenureSizeThreshold控制新生代直接晋升老年代的对象size阀值)不能进入到老年代,只要stop the world来暂停用户线程,执行GC清理。可以通过设置CMSInitiatingOccupancyFraction预留合适的CMS执行时剩余的空间
  • 新生代直接晋升到老年代的大对象超过了老年代的剩余空间,引发Full GC。注意于promotion failure的区别,promotion failure指的是Minor GC后发生的担保失败
  • Perm永久代空间不足会触发Full GC,可以让CMS清理永久代的空间。设置CMSClassUnloadingEnabled即可
  • System.gc()引起的Full GC,可以设置DisableExplicitGC来禁止调用System.gc引发Full GC

3. CMS不等于Full GC,很多人会认为CMS肯定会引发Minor GC。CMS是针对老年代的GC策略,原则上它不会去清理新生代,只有设置CMSScavengeBeforeRemark优化时,或者是concurrent mode failure的时候才会去做Minor GC

4. 什么情况下新生代对象会晋升到老年代?

  • 当对象大小超过了PretenureSizeThreshold设置的对象大小阀值时,对象直接在老年代分配空间
  • 当age从1开始的对象大小累计超过了Survivor区域的1/2(TargetSurvivorRatio所定义)时,会计算一个Thenuring Threshold,超过这个年龄的新生代对象会进入到老年代,即使这时候新生代还有很多的空间。注意MaxTenuringThreshold只是设置了最大的Thenuring Threshold,不是说只有大于Max Tenuring Threshold才会进入到老年代,而是只要超过了计算出来的Tenuring Threshold就会进入老年代,MaxTenuringThreshold规定了Tenuring Threshold的最大值而已。Tenuring Threshold这个值在每一轮GC后都会动态计算,它与TargetSurvivorRatio以及Survivor区的大小有关系,TargetSurivivor默认是50即Survivor的1/2, 会计算出一个Desired Survivor Size,当age从1开始的对象大小累计超过了这个Desired Survivor Size,那么这个age就是Tenuring Threshold的值

5. 一旦对象进入了老年代,那么只有触发CMS(只针对CMS而言)或者Full GC的时候才能被清除

6. Heap什么时候会发生OOM?

  • 当花在GC的时间超过了GCTimeLimit,这个值默认是98%
  • 当GC后的容量小于GCHeapFreeLimit,这个值默认是2%

7. 什么是剩余空间不够?

剩余空间不够不是说整体的空间不够分配某个对象,而是说连续的空间不够分配给某个对象。所以一旦内存碎片大多就可能发生剩余空间不够的问题,所以CMS这种收集器,需要在标记-清除几次之后进行压缩,进行优化。CMSFullGCsBeforeCompaction可以设置进行几次清除之后进行压缩

8. Full GC的次数说的是stop the world的次数,所以一次CMS至少会让Full GC的次数+2,因为CMS Initial mark和remark都会stop the world,记做2次。而CMS可能失败再引发一次Full GC

9. JMI默认会一个小时调用一次System.gc()清理缓存,所以可以DisableExplicitGC,也可以设置sun.rmi.dgc.client.gcInterval和sun.rmi.dgc.server.gcInterval参数来规定JMI清理的时间

10. 对于性能调优来说,应该理解对于给定的硬件,给定的算法(垃圾收集器),单个/多个线程单位时间内能够回收的空间是接近一个常量的。如果想要缩短GC的时候,就要考虑是否要相应调小空间

11. CMS收集器会了减少stop the world的时间,让GC线程和业务线程并发,这样也就相对拉长了CMS收集器单次GC的时间

12. 尽可能地让对象停留在新生代,因为新生代采用了复制算法,相对收回得更快,而且Minor GC的次数肯定比Full GC多,那么对象在新生代被清除的更能性会更高。而对象一旦进入到老年代,那么只有Full GC时才会回收,对象在整个系统停留的时间就会很长,很可能创建的它的线程早就死了,而它还活着

13. 为了尽可能让对象停留在新生代,就要注意设置Survivor区域的大小,因为它直接和对象是否进入老年代相关。之前就遇到过这种情况,明明新生代还有很大的空间,但是每次Minor GC后总是有对象进入到了老年代。后来发现由于Survivor太小,导致Tenuring Threshold为1,意思是年龄为1的对象大小超过了Survivor / 2(可通过TargetSurvivorRatio来调节,默认是50,即1/2),年龄只要超过1的对象这时候就要直接进入老年代了。而进入老年代,对象就只有在Full GC的时候才会被清除。而如果调大了Survivor空间,让对象对象尽量接近Max Tenuring Threshold时才进入到老年代,这时候会大大减少老年代的对象大小,并且让对象在新生代停留时间变长,提高了它们被快速清理出系统的概率。

最新文章

  1. Code of Conduct
  2. ElasticSearch大数据分布式弹性搜索引擎使用
  3. springMVC-数据的格式化
  4. rndc控制远程dns服务器配置方法
  5. Topself
  6. Spring+SpringMVC+Mybatis 利用AOP自定义注解实现可配置日志快照记录
  7. mvc存储Cookie和读取Cookie方法
  8. MFC CArchive实现保存到二进制文件
  9. Linux之批量挂载硬盘
  10. python 检测nginx状态,若无法访问发邮件通知
  11. Linux入门(2)_给初学者的建议
  12. MySQL学习笔记(七)使用AutoMySQLBackup工具自动备份MySQL数据库
  13. Redis 常用命令总结
  14. android sdk下载及安装教程
  15. Win10 calc.exe 无法打开计算器的解决方法
  16. c语言-遍历pci设备(1)io访问
  17. thinkphp前台模版字符串截取
  18. QTQuick控件基础(2)
  19. poi excel导入纯数字单元格显示科学计数法的处理
  20. 20个优秀的JavaScript 键盘事件处理库

热门文章

  1. Code First的实体继承模式
  2. [转]找到MySQL发生swap的原因
  3. p112 the podocyte
  4. MySQL的计算时间差
  5. STM32学习笔记
  6. 接口测试工具之Postman笔记
  7. macOS终端开启TAB键自动补全功能(不区分大小写)
  8. [转]语言模型训练工具SRILM
  9. 关于git的reset指令说明-soft、mixed、hard
  10. 我的书单(Book List)