加入收藏 | 设为首页 | 会员中心 | 我要投稿 应用网_丽江站长网 (http://www.0888zz.com/)- 科技、建站、数据工具、云上网络、机器学习!
当前位置: 首页 > 综合聚焦 > 资源网站 > 空间 > 正文

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

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

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

1.是否是并行 Full GC

(编辑:应用网_丽江站长网)

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

推荐文章
    热点阅读