行业资讯 2025年08月6日
0 收藏 0 点赞 684 浏览 2621 个字
摘要 :

文章目录 1. 监控表现 2. 问题推测 3. 工具使用 (1)定位应用程序的pid (2)研发自主进入机器上打dump: (3)分析工具的选取 4. 问题定位 1. 问题根因: 2. 解决方……




  • 1. 监控表现
  • 2. 问题推测
  • 3. 工具使用
    • (1)定位应用程序的pid
    • (2)研发自主进入机器上打dump:
    • (3)分析工具的选取
  • 4. 问题定位
  • 1. 问题根因:
  • 2. 解决方案:

本文关于JVM使用G1垃圾回收器出现老年代内存异常增加的问题,进行一系列分析排查。关于排查过程,包括查看机器的JVM情况、GC情况、堆配置参数等,并进行了heap dump分析。通过MAT工具分析dump文件,定位到了老年代上涨的原因是大对象直接分配到老年代,并提出了解决方案,即调整G1HeapRegionSize参数值大小。让我们来一起看一下具体的问题现象和解决过程。

一. 问题背景

通过公司系统监控发现线上环境一服务的老年代使用情况上下波动很大,时不时会触发高使用率报警。这里针对问题的分析和处理,做一个简单的回顾和总结。

垃圾收集器:G1,jdk环境:jdk8.

二. 排查过程

1. 监控表现

收到告警后,先去看了一下对应机器的JVM情况,可以发现JVM Mem Heap used中,老年代每隔几十分钟就会触发一次垃圾回收,然后很快占用率又会很快上涨到一个很高的水平.

JVM G1回收器老年代内存异常增加问题分析排查

而对比大部分正常的应用,老年代的占用相对都是比较平稳的,波动也不会那么剧烈.下面是一个正常应用的老年代生长曲线,和上图对比十分明显.

JVM G1回收器老年代内存异常增加问题分析排查

再看一下问题应用的GC情况,其中大对象分配(G1 Humongous Allocation)触发的Mixed GC非常规律,基本和老年代回收的节奏相匹配。

JVM G1回收器老年代内存异常增加问题分析排查

2. 问题推测

在机器上查看一下JVM的配置参数,发现region配置的大小为4M,那么超过2M的对象就会直接分配到老年代。通过监控初步推测,是G1垃圾收集器将大对象(超过region大小50%的对象)直接分配到老年代的region上,推测有可能存在周期性分配大对象直接到老年代,进而导致老年代不断上涨。

而老年代上涨的另外一种情况是年轻代对象在经过若干次survivor间的复制之后仍然未被young gc掉,最终被promoted到老年代,但是这种情况一般不会伴随Humongous Allocation。另外,通过监控也可以看到,问题应用的老年代上涨,主要就来源于allocated(大对象分配),所以可以把promoted的原因排除掉。

JVM G1回收器老年代内存异常增加问题分析排查

3. 工具使用

在有了初步的推测后,下一步就是有要看一下堆里面到底有些什么东西,这里自然少不了heap dump日志文件。

(1)定位应用程序的pid

在有问题的机器上查看应用程序的pid:

 ps -ef | grep java

(2)研发自主进入机器上打dump:

在lalaplat2容器页面上,登录到webterminal打dump,多个容器先在第一个容器上执行,指定生成目录到/tmp/下.

jmap -dump:format=b,file=/tmp/dump.hprof pid
参考: jmap -dump:format=b,file=/tmp/dump.hprof 1

补充说明:

map的dump参数有个live选项,加了live是指定dump内存中存活对象的快照,会强制触发一次full gc。不加的话则会dump堆中所有对象的快照。这次问题并未涉及到内存泄漏,而是想确认清楚到底是什么对象占据了大量老年代,因此没有加live参数,保留了内存中所有的对象。

(3)分析工具的选取

拿到dump文件,接下来就是要找一个趁手的工具去分析,我这边选用的是MAT.(Memory Analyzer)

说明:这里我使用的是1.11的版本,jdk8,内存设置4g。特别注意:使用MAT分析大的dump文件,需要调整MAT内存大小的。

JVM G1回收器老年代内存异常增加问题分析排查

关于MAT这里面需要特别提一下的是,可能有些同学有疑问,明明dump下来的文件非常大(比如对应的hprof文件有1.9G),或者监控上当时显示heap已经占用了好几个G,为什么工具上size显示的只有69.6M?

对于MAT来说,size默认展示的是存活对象的大小,那些在GC root上无法触达的对象(unreached)是没有计入的,一般来说这些对象是可以被垃圾回收器正常回收的,不是问题的关键所在,没有必要过多去关注。

可以看到截图上有313个unreachable objects,点进去一共有1.6个G左右。对unreachable objects的处理,其他工具如JProfiler也是类似。
当然你也可以选择在Preferences中把unreachable objects展示出来,如下图所示:

JVM G1回收器老年代内存异常增加问题分析排查

之后关闭MAT再重新加载hprof文件就可以看到包含unreachable objects的堆大小了。

JVM G1回收器老年代内存异常增加问题分析排查

特别说明:如果要查看unreachable objects的具体list明细value内容,是需要开启上述配置的,要不然是看不到的。

4. 问题定位

再回到老年代告警问题本身,我们打开Histogram来看一下堆上都有哪些巨大的对象。

JVM G1回收器老年代内存异常增加问题分析排查

可以看到有421w多char[]数组占据了大约670M以上的堆空间,64w多byte[]数组占据了356M以上的堆空间。分别点进outgoing reference去看一下具体的对象,可以看到每个char[]和byte[]对象都非常的大,占用了2M多的空间。

JVM G1回收器老年代内存异常增加问题分析排查

JVM G1回收器老年代内存异常增加问题分析排查

将value拷贝出来放到文本文件中,发现内容是Prometheus上报的监控数据,和/actuator/prometheus接口返回的内容是一致的。

这样就基本定位到了老年代上涨的”元凶”。仔细看了一下,monitor采集的指标数据都是正常的,不存在某个metric的label部分出现上千种组合而引发TooManyValue的情况。

三. 问题结论:

1. 问题根因:

G1HeapRegionSize设置不合理,而prometheus采集的指标数据超过region的50%引起的。

2. 解决方案:

加大region的大小,设置-XX:G1HeapRegionSize=8M。

注意:

(1)这个参数需要设置为2的幂次方,最小值是1M,最大值是32M。

另外,如果可以的话增加JVM堆大小(即-Xmx -Xms),这里是只采用了增加region大小的方式。

(2)添加配置中,注意参数的先后顺序。

下面是PRE环境调整region大小前后的对比监控曲线:

调整前:

JVM G1回收器老年代内存异常增加问题分析排查

调整后:

JVM G1回收器老年代内存异常增加问题分析排查

以上就是关于JVM G1回收器老年代内存异常增加问题分析排查的全部内容,希望对你有帮助,其实JVM调优还是需要深入理解垃圾回收器的原理,这样有助于我们分析的方向,只有方向对了,才能找到正确的解决方案。

微信扫一扫

支付宝扫一扫

版权: 转载请注明出处:https://www.zuozi.net/10156.html

管理员

相关推荐
2025-08-06

文章目录 一、Reader 接口概述 1.1 什么是 Reader 接口? 1.2 Reader 与 InputStream 的区别 1.3 …

988
2025-08-06

文章目录 一、事件溯源 (一)核心概念 (二)Kafka与Golang的优势 (三)完整代码实现 二、命令…

465
2025-08-06

文章目录 一、证明GC期间执行native函数的线程仍在运行 二、native线程操作Java对象的影响及处理方…

348
2025-08-06

文章目录 一、事务基础概念 二、MyBatis事务管理机制 (一)JDBC原生事务管理(JdbcTransaction)…

456
2025-08-06

文章目录 一、SnowFlake算法核心原理 二、SnowFlake算法工作流程详解 三、SnowFlake算法的Java代码…

517
2025-08-06

文章目录 一、本地Jar包的加载操作 二、本地Class的加载方法 三、远程Jar包的加载方式 你知道Groo…

832
发表评论
暂无评论

还没有评论呢,快来抢沙发~

助力内容变现

将您的收入提升到一个新的水平

点击联系客服

在线时间:08:00-23:00

客服QQ

122325244

客服电话

400-888-8888

客服邮箱

122325244@qq.com

扫描二维码

关注微信客服号