加入收藏 | 设为首页 | 会员中心 | 我要投稿 东莞站长网 (https://www.0769zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 资源网站 > 空间 > 正文

JVM发生CMS GC的 5 种情况,你知道的肯定不全!

发布时间:2019-06-13 10:55:13 所属栏目:空间 来源:涤生YQ
导读:副标题#e# 经常有同学会问,为啥我的应用 Old Gen 的使用占比没达到 CMSInitiatingOccupancyFraction 参数配置的阈值,就触发了 CMS GC,表示很莫名奇妙,不知道问题出在哪? 其实 CMS GC 的触发条件非常多,不只是 CMSInitiatingOccupancyFraction 阈值触发
副标题[/!--empirenews.page--]

经常有同学会问,为啥我的应用 Old Gen 的使用占比没达到 CMSInitiatingOccupancyFraction 参数配置的阈值,就触发了 CMS GC,表示很莫名奇妙,不知道问题出在哪?

JVM发生CMS GC的 5 种情况,你知道的肯定不全!

其实 CMS GC 的触发条件非常多,不只是 CMSInitiatingOccupancyFraction 阈值触发这么简单。本文通过源码全面梳理了触发 CMS GC 的条件,尽可能的帮你了解平时遇到的奇奇怪怪的 CMS GC 问题。

先抛出一些问题,来吸引你的注意力。

  • 为什么 Old Gen 使用占比仅 50% 就进行了一次 CMS GC?
  • Metaspace 的使用也会触发 CMS GC 吗?
  • 为什么 Old Gen 使用占比非常小就进行了一次 CMS GC?

触发条件

CMS GC 在实现上分成 foreground collector 和 background collector。foreground collector 相对比较简单,background collector 比较复杂,情况比较多。

下面我们从 foreground collector 和 background collector 分别来说明他们的触发条件:

说明:本文内容是基于 JDK 8

说明:本文仅涉及 CMS GC 的触发条件,至于算法的具体过程,以及什么时候进行 MSC(mark sweep compact)不在本文范围

foreground collector

foreground collector 触发条件比较简单,一般是遇到对象分配但空间不够,就会直接触发 GC,来立即进行空间回收。采用的算法是 mark sweep,不压缩。

background collector

说明 background collector 的触发条件之前,先来说下 background collector 的流程,它是通过 CMS 后台线程不断的去扫描,过程中主要是判断是否符合 background collector 的触发条件,一旦有符合的情况,就会进行一次 background 的 collect。

  1. void ConcurrentMarkSweepThread::run() {  
  2. ...//省略  
  3. while (!_should_terminate) {  
  4. sleepBeforeNextCycle();  
  5. if (_should_terminate) break;  
  6. GCCause::Cause cause = _collector->_full_gc_requested ?  
  7. _collector->_full_gc_cause : GCCause::_cms_concurrent_mark;  
  8. _collector->collect_in_background(false, cause);  
  9. }  
  10. ...//省略  
  11. }  

每次扫描过程中,先等 CMSWaitDuration 时间,然后再去进行一次 shouldConcurrentCollect 判断,看是否满足 CMS background collector 的触发条件。CMSWaitDuration 默认时间是 2s(经常会有业务遇到频繁的 CMS GC,注意看每次 CMS GC 之间的时间间隔,如果是 2s,那基本就可以断定是 CMS 的 background collector)。

  1. void ConcurrentMarkSweepThread::sleepBeforeNextCycle() {  
  2. while (!_should_terminate) {  
  3. if (CMSIncrementalMode) {  
  4. icms_wait();  
  5. if(CMSWaitDuration >= 0) {  
  6. // Wait until the next synchronous GC, a concurrent full gc  
  7. // request or a timeout, whichever is earlier.  
  8. wait_on_cms_lock_for_scavenge(CMSWaitDuration);  
  9. }  
  10. return;  
  11. } else {  
  12. if(CMSWaitDuration >= 0) {  
  13. // Wait until the next synchronous GC, a concurrent full gc  
  14. // request or a timeout, whichever is earlier.  
  15. wait_on_cms_lock_for_scavenge(CMSWaitDuration);  
  16. } else {  
  17. // Wait until any cms_lock event or check interval not to call shouldConcurrentCollect permanently  
  18. wait_on_cms_lock(CMSCheckInterval);  
  19. }  
  20. }  
  21. // Check if we should start a CMS collection cycle  
  22. if (_collector->shouldConcurrentCollect()) {  
  23. return;  
  24. }  
  25. // .. collection criterion not yet met, let's go back  
  26. // and wait some more  
  27. }  
  28. }  

那 shouldConcurrentCollect() 方法中都有哪些条件呢?

  1. bool CMSCollector::shouldConcurrentCollect() { 
  2. // 第一种触发情况 
  3. if (_full_gc_requested) { 
  4. if (Verbose && PrintGCDetails) { 
  5. gclog_or_tty->print_cr("CMSCollector: collect because of explicit " 
  6. " gc request (or gc_locker)"); 
  7. } 
  8. return true; 
  9. } 
  10. // For debugging purposes, change the type of collection. 
  11. // If the rotation is not on the concurrent collection 
  12. // type, don't start a concurrent collection. 
  13. NOT_PRODUCT( 
  14. if (RotateCMSCollectionTypes && 
  15. (_cmsGen->debug_collection_type() != 
  16. ConcurrentMarkSweepGeneration::Concurrent_collection_type)) { 
  17. assert(_cmsGen->debug_collection_type() != 
  18. ConcurrentMarkSweepGeneration::Unknown_collection_type, 
  19. "Bad cms collection type"); 
  20. return false; 
  21. } 
  22. ) 
  23. FreelistLocker x(this); 
  24. // ------------------------------------------------------------------ 
  25. // Print out lots of information which affects the initiation of 
  26. // a collection. 
  27. if (PrintCMSInitiationStatistics && stats().valid()) { 
  28. gclog_or_tty->print("CMSCollector shouldConcurrentCollect: "); 
  29. gclog_or_tty->stamp(); 
  30. gclog_or_tty->print_cr(""); 
  31. stats().print_on(gclog_or_tty); 
  32. gclog_or_tty->print_cr("time_until_cms_gen_full %3.7f", 
  33. stats().time_until_cms_gen_full()); 
  34. gclog_or_tty->print_cr("free="SIZE_FORMAT, _cmsGen->free()); 
  35. gclog_or_tty->print_cr("contiguous_available="SIZE_FORMAT, 
  36. _cmsGen->contiguous_available()); 
  37. gclog_or_tty->print_cr("promotion_rate=%g", stats().promotion_rate()); 
  38. gclog_or_tty->print_cr("cms_allocation_rate=%g", stats().cms_allocation_rate()); 
  39. gclog_or_tty->print_cr("occupancy=%3.7f", _cmsGen->occupancy()); 
  40. gclog_or_tty->print_cr("initiatingOccupancy=%3.7f", _cmsGen->initiating_occupancy()); 
  41. gclog_or_tty->print_cr("metadata initialized %d", 
  42. MetaspaceGC::should_concurrent_collect()); 
  43. } 
  44. // ------------------------------------------------------------------ 
  45. // 第二种触发情况 
  46. // If the estimated time to complete a cms collection (cms_duration()) 
  47. // is less than the estimated time remaining until the cms generation 
  48. // is full, start a collection. 
  49. if (!UseCMSInitiatingOccupancyOnly) { 
  50. if (stats().valid()) { 
  51. if (stats().time_until_cms_start() == 0.0) { 
  52. return true; 
  53. } 
  54. } else { 
  55. // We want to conservatively collect somewhat early in order 
  56. // to try and "bootstrap" our CMS/promotion statistics; 
  57. // this branch will not fire after the first successful CMS 
  58. // collection because the stats should then be valid. 
  59. if (_cmsGen->occupancy() >= _bootstrap_occupancy) { 
  60. if (Verbose && PrintGCDetails) { 
  61. gclog_or_tty->print_cr( 
  62. " CMSCollector: collect for bootstrapping statistics:" 
  63. " occupancy = %f, boot occupancy = %f", _cmsGen->occupancy(), 
  64. _bootstrap_occupancy); 
  65. } 
  66. return true; 
  67. } 
  68. } 
  69. } 
  70. // 第三种触发情况 
  71. // Otherwise, we start a collection cycle if 
  72. // old gen want a collection cycle started. Each may use 
  73. // an appropriate criterion for making this decision. 
  74. // XXX We need to make sure that the gen expansion 
  75. // criterion dovetails well with this. XXX NEED TO FIX THIS 
  76. if (_cmsGen->should_concurrent_collect()) { 
  77. if (Verbose && PrintGCDetails) { 
  78. gclog_or_tty->print_cr("CMS old gen initiated"); 
  79. } 
  80. return true; 
  81. } 
  82. // 第四种触发情况 
  83. // We start a collection if we believe an incremental collection may fail; 
  84. // this is not likely to be productive in practice because it's probably too 
  85. // late anyway. 
  86. GenCollectedHeap* gch = GenCollectedHeap::heap(); 
  87. assert(gch->collector_policy()->is_two_generation_policy(), 
  88. "You may want to check the correctness of the following"); 
  89. if (gch->incremental_collection_will_fail(true /* consult_young */)) { 
  90. if (Verbose && PrintGCDetails) { 
  91. gclog_or_tty->print("CMSCollector: collect because incremental collection will fail "); 
  92. } 
  93. return true; 
  94. } 
  95. // 第五种触发情况 
  96. if (MetaspaceGC::should_concurrent_collect()) { 
  97. if (Verbose && PrintGCDetails) { 
  98. gclog_or_tty->print("CMSCollector: collect for metadata allocation "); 
  99. } 
  100. return true; 
  101. } 
  102. return false; 
  103. } 

上述代码可知,从大类上分, background collector 一共有 5 种触发情况:

1.是否是并行 Full GC

(编辑:东莞站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

推荐文章
    热点阅读