emmetyang

导航

 

1.用到的工具主要有:jvisualvm  ,IBM HeapAnalyer(主要是堆分析工具)(下载地址:https://www.ibm.com/support/pages/ibm-heapanalyzer)java -jar ha457.jar

2.业务场景说明:公司商城product 模块突然某一天(之前运行的是平稳的)堆内存一直在慢慢飙升,最后直接导致 out of memoey。

3.解决分析思路:

排查分析

现象分析

发现现象: Old区爆满,Eden区爆满

Old区爆满属于不太正常的现象,通常情况下大多数对象会在Eden区就被回收,能进入Old区的对象是较少的,因此要么是并发量过大,系统不足以支撑这样的并发,要么是系统存在无法回收的对象致使Old被撑爆也就是疑似内存泄漏。

验证分析

在怀疑系统中存在内存泄漏问题后开始排查代码是否存在可能的内存泄漏问题,发现一处可能的地点,针对这一部分进行压力测试

开始设置线程数为50,爆内存,之后将线程数设置为25,Old区稳定在高位(800-1000M左右),在压力卸掉后Old区依旧稳定在较高位置(600M),较为符合内存泄漏表现

进一步验证

多次进行压力测试后发现现象稳定复现,再对同一模块其他接口进行压测,发现出现同样的现象,对堆内存进行dump后发现堆内存中存在占用空间极大的byte[]对象,每个数组对象开辟了10008208个对象空间。

改进压测思路,先进行10个线程的压测,待内存稳定后进行25个线程的压测,待内存稳定后再次切换会10个线程的压测,发现Old区空间稳定在25个线程时的水平,没有继续增加,遂怀疑与系统中的最大连接相关。

再次分析

使用ha对堆dump进行分析后发现所有的byte[]对象都是被org.apache.coyote.Request对象持有的,怀疑是tomcat导致的现象,因此考虑替换web容器进行对比测试

再次验证

替换web容器为undertow进行压测,发现所有接口压测是Old区都维持在较低水平(80-120M)且在压力卸掉后Old能回收到50-60M左右,确定是tomcat导致的Old区高占用

深入分析

之前只是看到内存中存在大容量的byte[]对象,并没有看到其中的内容,因此改用MAT继续查看堆dump,这次看到这些byte[]中存储的是请求相关的信息

 GET /o2ostock/getByBarcodes?storeLatitude=22.534576&storeLongitude=113.973016&cityId=873&barcodes=0000035&barcodes=0000151 HTTP/1.1..content-type:application/json;charset=UTF-88..accept:*/**..user-agent:Java/1.8.0_1811..host:test21133.star365.com:90166..co... 

发现虽然分配了10008208个空间,但实际使用的远没有这么大,绝大部分的空间是存储的0,其次是对象虽然很大,但数量却不多。

接着查看线程相关信息,发现http-nio-9016-exce-xx线程的数量与这个对象的数量一致。

搜索了tomcat相关的信息并且阅读了相关部分的代码,怀疑是每个tomcat的工作线程持有一个org.apache.coyote.Request对象,而这个对象又持有一个byte[]对象,与科总沟通后发现配置中有这么一条配置与byte[]对象的大小十分接近

server.max-http-header-size=10000000

将配置改为1000000后再次对product模块进行压测,Old区在50个线程时维持在160M左右,基本可以确定该配置影响了服务器资源

分析dump 文件找到占用最多内存的对象和实体类

 

压测看堆内存变化

 

压测图:

 

总结:jvm内存排查问题是需要不断猜测和结合排查工具慢慢的区查找,发现问题所在的,并不是一下子就能找到解决,需要我们静心,仔细的去发现问题,这个过程是比较有意义的,愿天下所有的程序员能无jvm问题。

 参考gc 调优参数:https://blog.csdn.net/axela30w/article/details/106307548

posted on 2022-04-14 18:29  emmetyang  阅读(273)  评论(0)    收藏  举报