性能文章>记一次线上内存过高的问题解决>

记一次线上内存过高的问题解决原创

https://a.perfma.net/img/2382850
1年前
5741214

本文正在参加「Java应用线上问题排查经验/工具分享」活动

背景

线上**-product-center服务器发现有报警,
image.png

从报警看出内存占用过高,开始定位问题

解决

去有问题的服务器看cpu负载,通过top命令
image.png
一开始打算看log找问题,但是不好定位,只是看到log日志有大的对象输出,其实这里大概能看出有程序大对象的问题,但是优化过一版本之后还是偶尔会有报警出来。
后来通过jstack命令看能不能发现一些端倪,结果发现并无卵用,可能自家内功修炼还不够并未发现问题~
image.png
通过 top -Hp pid找到cpu过高的进程,转换16进制,可以使用linux自带命令printf "%x\n" pid,通过jstack pid |grep tid看打印结果
image.png
这里的VM Thread一行显示nid=0x2165,这里nid的意思就是操作系统线程id的意思。而VM Thread指的就是垃圾回收的线程,而此线程刚刚cpu负载比较高,这里我们基本上可以确定,当前系统缓慢的原因主要是垃圾回收过于频繁,导致GC停顿时间较长。
下图FGC次数为8,比较正常。
image.png
当时没有截图记得当时的FGC值是六百多次,而且每次一旦cpu过高FGC次数就会增长较快,可进一步确认是内存溢出或者程序有大对象导致。当时jmap -dump:format=b,file=/home/admin/logs/heap.hprof pid dump出内存日志。但是线上服务器下载大文件容易影响线上IO,然后在线上安装了rclone上传到文件服务器,然后在本地pc安装rclone下载文件。通过MAT工具打开,下面直接贴图,看图就可察觉到问题了。
用MAT打开一个hprof文件后一般会进入如下的overview界面,或者和这个界面类似的leak suspect界面,overview界面会以饼图的方式显示当前消耗内存最多的几类对象,可以使我们对当前内存消耗有一个直观的印象
image.png
image.png
以直方图的方式来显示当前内存使用情况可能更加适合较为复杂的内存泄漏分析
shallow heap:指的是某一个对象所占内存大小。
retained heap:指的是一个对象的retained set所包含对象所占内存的总大小。
image.png
image.png
经过mat工具分析之后,我们基本上就能确定内存中主要是哪个对象比较消耗内存,然后找到该对象的创建位置,进行处理即可,这里主要是ArrayList最对,关键词也是java.lang.Object[],可以看出大对象导致大量Full GC。
到此已定位到问题,更改代码发版解决。

小结

此次问题第一天没有找出来,没来得及dump出堆栈信息,第二天才解决。
对于线上的系统突然产生的问题,如果问题导致服务不可用,首先要做的导出jstack和内存信息,查看当时问题记录,然后重启系统,尽快保证服务可用性。
一般线上服务cpu较高以及full gc过多不外乎几种情况:大对象过多或者数据量过大导致Full GC频繁从而系统缓慢,另外的或者有比较耗CPU的计算工作;另外有些有可能有死循环或者锁使用不当导致死锁等。
稍微总结下步骤:

  通过`jps`或者`ps -ef|grep java`找到java进程pid;
  通过`top` 查看cpu情况,如果cpu过高,通过`top -Hp pid`查看当前进程的各个线程情况,找到cpu过高的线程;
  通过`printf "%x\n" pid` 命令转换16进制;
  通过`jstack pid |grep tid`查看线程工作:如果是正常的用户线程,则通过该线程的堆栈信息查看其具体是在哪处用户代码处运行比较消耗CPU;如果该线程是`VM Thread`,则通过`jstat -gcutil pid time  `命令监控当前系统的GC状况,然后通过`jmap dump:format=b,file= `导出系统当前的内存数据。导出之后将内存情况放到MAT工具中进行分析即可得出内存中主要是什么对象比较消耗内存,进而可以处理相关代码;

另外我们也可以多用jstat -gcutil pid time多关注下ygc以及fgc次数
image.png
当然问题出来了,我们平时可以怎么避免尽量减少这种情况的发生呢?个人认为代码的严谨性是第一位。

分类:
标签:
请先登录,再评论

👍

10月前

性能问题真的很考验代码的严谨性啊!

111月前

为你推荐

从一起GC血案谈到反射原理
前言 首先回答一下提问者的问题。这主要是由于存在大量反射而产生的临时类加载器和 ASM 临时生成的类,这些类会被保留在 Metaspace,一旦 Metaspace 即将满的时候,就会触发 Fu
JVM 源码解读之 CMS 何时会进行 Full GC
前言 本文内容是基于 JDK 8在文章[ JVM 源码解读之 CMS GC 触发条件](https://heapdump.cn/article/190389) 中分析了 CMS GC 触发的
FGC实战:如何用Idea揪出开源组件调用System.gc导致频繁FGC
某天上午收到最近发布的一个服务频繁FGC的告警,这个服务只是给公司内部相关人员使用的,并非给互联网用户提供服务的系统。而且功能也比较简单,就是查看一些统计信息、报表数据、数据导出Excel等,访问量非
一个诡异的full gc查找问题
背景一个服务突然所有机器开始频繁full gc。而服务本身没有任何改动和发布记录。上线查看gc log日志,日志如下:从日志来看,每次发生full gc的时候都比较奇怪,主要有两点,第一、old区域和
Redis client链接池配置不当引起的频繁full gc
现象笔者负责的一个RPC服务就是简单的从Redis Cluster中读取数据,然后返回给上游。理论上该服务的对象大部分都应该是朝生夕死的,但是笔者查看gc log 的时候发现 age =2 的对象还真
java内存溢出问题分析过程
背景运维人员反馈一个容器化的java程序每跑一段时间就会出现OOM问题,重启后,间隔大概两天后复现。 问题调查 一、查日志由于是容器化部署的程序,登上主机后使用docker logs Containe
为什么容器内存占用居高不下,频频 OOM(续)
在之前的文章《[为什么容器内存占用居高不下,频频 OOM](https://heapdump.cn/article/1589003)》 中,我根据现状进行了分析和说明,收到了很多读者的建议和疑
System.gc() 源码解读
介绍```System.gc()```,大家应该也有所了解,是JDK提供的触发Full GC的一种方式,会触发Full GC,其间会stop the world,对业务影响较大,一般情况下不会直接使用