记一次内存泄漏问题排查

问题描述
某应用上线几天后,出现了访问速度非常慢的情况,通过日志发现是堆内存溢出错误:java.lang.OutOfMemoryError: Java heap space。但是为什么会内存溢出呢?这个应用按说不需要太多内存。实在百思不解,于是进行了下面的排查:
先看一下进程的资源使用情况:

top

记一次内存泄漏问题排查
文章图片
1.png
果然cpu飙得厉害,没猜错的话应该是频繁full gc导致的,于是看一下gc情况:
jstat -gcutil 1 5000

记一次内存泄漏问题排查
文章图片
2.1.png 这不看不知道,一看吓一跳啊!FullGc 25万多次,Full Gc用时9万多秒,这样的程序不慢才怪啊。是什么原因导致这么频繁的full gc呢?能不能再深入查一查呢?
于是用下面命令生成一个dump文件:
jmap -dump:live,file=dump_001.bin 1

【记一次内存泄漏问题排查】启动本地jvisualvm,再把Dump文件下载后导入到jvisualvm中:

记一次内存泄漏问题排查
文章图片
3.png 果然看到了内存占用情况,但Byte[]是什么鬼实在不明白?那就再找找别的对象看看:

记一次内存泄漏问题排查
文章图片
4.png
记一次内存泄漏问题排查
文章图片
5.png
找到了kafka相关,what?难道kafka有bug?不应该吧?还是去看看这个项目跟kafka有关的代码是怎么写的吧。既然提示是channel那应该跟连接有关,就顺着这个思路找下去,果然发现了问题:

记一次内存泄漏问题排查
文章图片
6.png
记一次内存泄漏问题排查
文章图片
7.png
简单分析一下这位同学写的代码,就是通过redis里的key循环去发kafka消息,结果每次都创建了一个kafka的producer对象,而且该方法是static的,不能释放掉,所以就造成了内存泄漏。
结束语:平时写程序时还是要谨慎一些,平时还是需要去理解jvm内存结构,这样自己写的代码可以做到心中有数,不至于造成大问题。

    推荐阅读