一个技术总监需要知道JVM的GC机制吗,需要知道JVM是如何并行GC的吗?
作者:卡卷网发布时间:2025-01-09 18:34浏览数量:90次评论数量:0次
阿里P8技术官:搞Ja开发的,看懂JVM的GC志的很重要!!
前言
今天整理的这篇文章,整理自以前记录的常笔记。
刚开始接触JVM时,对待GC的志,是保持"逃避"态度的,线上部署的程序没有达到期望的运行效率,或是预期目标时,往往会把问题的矛头指向内存上。
是不是内存不够?
GC志怎么这么多?占用磁盘高达几个G?
不想看到打印怎么多,甚至暴力的将程序志屏蔽掉。
我也曾经这样干过,写过的程序,同样导致过内存溢出,甚至是主机宕机。
是的,ja中的回收的确帮我们省了很多事,我们不像C/C++程序员一样,
需要考虑分配(malloc)内存分配与(free)释放内存,但我相信每个ja开发的小伙伴都
会遇到GC问题,无论是在程序的性能优化,还是故障分析上。
我们应该在一次又一次的失误中获得经验和教训,而不是去逃避或是解决问题了事。同样的知识点,回顾两次,就会产生1+1>2的效应。
所以这篇文章我们来谈谈耳熟能详的JVM的GC志。
GC志是什么
首先来说一说GC的概念,GC就是回收(GarageCollection)的缩写。
何为?
没有任何引用指向的对象,被JVM视为。
当然,对应的判定算法有:引用计数算法、可达性分析算法。对应的回收算法有:标记清除、复制、标记整理、分代收集算法。
那GC的志是什么呢?
GC志是ja虚拟机产生的一种描述性的文本志。就像我们开发ja程序需要输出log志一样。JA虚拟机用GC志来描述,回收的情况。
minorGC和MajorGC
MinorGC,表示新生代GC,指发生在新生代的收集动作,所有的MinorGC都会触发全世界的暂停(stop-the-world),停止应用程序的线程,不过这个过程非常短。
MajorGC:老年代GC,指发生在老年代的GC,也称之为FullGC。
GC志有什么用
通过GC志,我们能直观的看到内存清理的基本工作过程。
了解回收的一些行为,何时在Young(年轻代)何时在回收Old(老年代),并且展示回收使用到多少资源。
尽管现在Ja程序的可视化监控工具已经很多了【介绍?】,但是GC志对于开发人员来说,是我们快速定位潜在的内存故障和性能瓶颈最直观的信息之一。
<>通过GC志我们能获取什么信息?>
ES的GC分配失败(GCAllocationFaile)
遇到线上GC问题时的志也是很宝贵的分析素材,这里的GCAllocationFaile图片引用自一位群友的ES节点GC志。
GCAllocationFaile是我们经常遇到的一种GC志。
分配失败代表着在JVM的Eden区中没有更多的空间来分配对象了,这是minorGC的正常志。
那别光说不练,那我们来看看GCAllocationFaile的志内容是什么样的。
是不是感觉很乱?【抠脑袋图对话】
没关系,我们依次来分析分析。
我们按时间分割,可以知道,截图中一共有两行志,先来看志一:
毋庸置疑,首先映入眼帘的是带时区的志时间。
其次Totaltimeforwhichapplicationthreadswerestopped表示所有应用线程暂停了0.0313360秒。
其中等待所有应用线程到达【安全点】用了0.0000925秒。
暂停的这段时间,其实就是花在了GC上面。后续第二行的real=0.03se和这里相对应。
刚才提到了安全点,那简单提一提,我们知道在Ja的线程有几个不同的状态。也知道线程如果被“打断”会出现什么样的问题。所以对于设计者来说,需要让线程“跑”到安全点上,再停顿。当处于安全点时,线程的状态是确定的,这样JVM就可以安全的进行一些作,如执行回收。
安全点的位置包括:
如果有线程一直没有进入到安全点,就会导致GC时JVM停顿时间延长。
再来看志二:
第一行,为志输出的时间。
第二行,表明了进行了一次GC回收,注意,由于这里没有Full关键字,表明是一次MinorGC,并指明了GC的时间。AllocationFaile则表示GC的原因是在年轻代中没有了足够的空间来存储数据了。
第三行,ParNew同样指明了本次GC是发生在年轻代,并且使用的是ParNew收集器。该收集器采用复制算法回收内存,期间会停止工作线程,即StopTheWorld。
第三、四、五行,表示每次年轻代GC之后打印svivor区域内对象的年龄分布,threshold则表示设置的晋升老年代的年龄阈值为6。
第六行,分别表示GC前年轻代的使用容量,GC后该区域使用容量,括号内是该区域的总容量。最后是该内存区域GC耗时,单位是秒。
第七行,分别表示堆内存在回收之间的大小、堆内存在回收之后的大小,堆区的总大小。
可以看到在GC后,回收对象占很少。
第八行,显示三个耗时,分别是用户态耗时、内核态耗时、总耗时。
从以上信息我们可以分析得出以下结论:
本次GC新生代减少了:149828-8895=140933K。
堆内存区域共减少了:6272826-6139400=133426K。
图来自网络
再把两个等号后的结果相减:140933-133426=7507K
说明该次共有7507K(7.3M)内存从年轻代移到了老年代,可以看出来数量并不多,说明都是生命周期短的对象,只是这种对象有很多。
我们需要的是尽量避免FullGC的发生,让对象尽可能的在年轻代就回收掉,所以这里可以稍微增加一点年轻代的大小,让那7.3M的数据也保存在年轻代中。
ES的OldGC
上面介绍了年轻代的GC志,下面我们来说一说老年代的GC志,其实和年轻代分析的方法一样。
还是先列出志:
直接来解释一下吧。第一行指明了这是第238384次GC在最近2.3s内花了2.2s用来做收集。
相信解读过年轻代的GC,理解第二行的含义并不复杂了。
[gc][本次是oldGC][这是第228385次GC检查][从JVM启动至今发生的第160772次GC]dation[本次检查到的GC总耗时5秒,可能是多次的加和],
collections[从上次检查至今总共发生1次GC]/[从上次检查至今已过去5.1秒],
total[本次检查到的GC总耗时为5秒]/[从JVM启动至今发生的GC总耗时为4.4天],
memory[GC前Heapmemory空间]->[GC后Heapmemory空间]/[Heapmemory总空间],
all_pools(分代部分的详情)
{[young区][GC前Memory]->[GC后Memory]/[young区Memory总大小]}
{[svivor区][GC前Memory]->[GC后Memory]/[svivor区Memory总大小]}{[old区][GC前Memory]->[GC后Memory]/[old区Memory总大小]}
ES的GC配置
-XX:+Printetails表示打印GC的详细志
-XX:+PrintateStamps表示需要展示打印GC的期时间
-XX:+
志动,输出到指定的志文件中等等配置。
GC志图示
如果前面的介绍还没有太明白,这里附上两张GC志的图片,以后遇到需要阅读GC志的时候,可以用作工具查阅。
年轻代:
老年代:
总结(我的观点)
GC涉及到的知识点很多,本文可能只是冰山一角,从GC志出发分析,让读者了解,GC志中每个数字的变化,意味着什么。更多的,先前有介绍过线上OOM的一些排查思路和MAT性能分析工具在实际案例中的使用,同时希望各位多多结合实际的案例来分析,做好知识储备,即是线上出了GC的一些问题也能做到成竹在胸,调整出最优的JVM配置,提高线上程序的运行效率,尽量避免性能上的一些故障。最后在内容上做个小结
免责声明:本文由卡卷网编辑并发布,但不代表本站的观点和立场,只提供分享给大家。
你 发表评论:
欢迎