当前位置: 首页 > 后端技术 > Java

记得排查oom问题

时间:2023-04-01 21:32:35 Java

大家好,我是大斌~今天给大家分享一下最近的OOM问题。上周五上午,测试同学反映测试环境子系统服务超时,请求没有响应。接到这个问题后,我有些疑惑。系统最近没改代码逻辑,怎么会突然报服务超时的问题。为了避免影响测试进度,我赶紧登录堡垒机查看日志,看看是怎么回事。先看系统负载,使用top命令查看。发现其中一个Java进程cpu一直卡在100%到200%之间。因为这个系统不涉及大量计算的逻辑,所以可以猜测要么是死循环问题,要么是频繁fullgc导致的。查看系统日志,发现出现java.lang.OutOfMemoryError:Metaspace。显然,元空间中的内存溢出了。然后查看系统gc状态,使用如下命令查看。pid是对应的Java进程id,通过top命令获取。参数1000表示每1000ms打印一条记录。jstat-gcpid1000看执行结果,不出所料,从应用启动到采样,fullgc已经触发了数百次!这就是为什么cpu始终处于100%的原因。还有一个参数MC(metaspaceallocationmemorysize),已经接近设置的最大元空间大小(配置--XX:MaxMetaspaceSize=128m)。这里也简单介绍一下元空间。元数据是jdk8中特有的一种数据结构。jdk7称为permanentgeneration,jdk8permanentgeneration将被废弃,取而代之的是metaspace。元空间分配在本地内存(不在堆上),默认不限制内存使用。您可以使用MaxMetaspaceSize来指定最大值。metaspace由两部分组成:KlassMetaspace,用来存放klass,klass是jvm中class文件的运行时数据结构。NoKlassMetaspace专门用来存放其他与klass相关的内容,比如方法,常量池等,这个内存由多块内存组成。MC为KlassMetaspace和NoKlassMetaspace分配的总内存大小,单位为KB。上图中,MC已经接近metaspace设置的上限,也就是此时metaspace内存不够用,导致一直触发fullgc。然后分析转储内存,看看是什么原因导致元空间内存溢出。使用命令./jmap-dump:live,format=b,file=/xxx将内存堆导出到xxx位置(hprof格式),然后使用MAT工具进行分析。将hprof文件导入MAT工具,打开内存泄漏分析(涉及公司内部源码,所以是马赛克):看到这里,你大概就知道问题出在哪里了。因为公司最近在推广一个漏洞监控工具,需要在服务器端部署一个代理程序。该工具将在应用程序运行时收集和监控功能执行和数据传输,并可以识别常见的安全缺陷和漏洞。而编码部分是该漏洞监测工具的应用包名,这很可能是引入该工具造成的!进一步确认问题。OpenHistogram:ShallowHeap表示一个对象结构本身占用的内存大小,不包括其属性引用对象占用的内存。RetainedHeap是对象被GC回收后可以释放的内存大小,等于被释放对象的RetainedHeap中所有对象的ShallowHeaps的总和。在Histogram视图中,选中其中一个类点击鼠标右键弹出菜单,选择MergeshortestpathstoGCRoots可以查看当前对象到GCRoot的路径,过滤某些类型的引用。结果如下:漏洞监控工具类别占用内存最多,基本可以确定问题所在。最后去掉漏洞监控工具重新部署后,就不会出现服务超时的问题了。以上就是本期OOM问题分析的全过程啦~码字不易,如果觉得对你有帮助,可以点个赞鼓励一下!我是大斌,一名程序员,专注于Java后端硬核知识分享。欢迎大家关注~本文由博客发布平台OpenWrite发布!