【诊断】linux系统下的内存溢出问题定位

步骤:

        (1)编写并运行一个会造成内存溢出的代码

import java.util.HashMap;
import java.util.concurrent.atomic.AtomicInteger;

public class HeapLeakTest {

    static AtomicInteger i = new AtomicInteger(1);

    public static void main(String[] args) {

        HashMap<String, Integer> map = new HashMap<>();
        while (true) {

            map.put(new String("第" + i.get() + "个对象"), i.get());
            i.incrementAndGet();
        }
    }
}

        在死循环中不断创建String对象和Integer对象,map不能及时释放无用对象的内存资源,模拟内存溢出。

        (2)使用top命令查看所有进程使用系统资源的情况

        可以看到9180进程(Java程序)CPU占用率异常。

        (3)使用top -H -p 9180查看进程下每一个线程使用CPU的情况

        可以看到9182、9183、9184、9185、9186、9187、9188、9189等线程的CPU占用率异常。

        (4)通过jstack 9180 > log.txt命令将Java程序的堆栈信息打印到log.txt中,使用cat log.txt | grep 0x23df(线程id的十六进制形式)过滤出异常线程的信息

        我们可以看到,这些CPU使用率异常的线程都是GC线程,那么CPU使用率异常问题的产生原因肯定在堆内存中了。

        (5)通过jstat -gcutil 9180 2000 10命令查看实时堆内存使用情况

        其中FGC(Full GC)次数最高达到137次,FGCT(Full GC Time)总时间为67s,每次Full GC耗时:67 / 137 ≈ 0.5s。要知道Full GC是会stop the world(暂停其它用户线程的运行)的,Java进程绝大部分时间都用于GC就没有时间去做其他事了。

        (6)使用jmap -histo 9180命令,查看哪些类对象占用内存较多

        这里截取了占用内存资源的TOP10([C指char数组,String底层是char数组),我们发现主要是new了大部分的String对象、Integer对象存储在HashMap中,又没有即时清理HashMap中的无用数据导致内存溢出。

总结:

        1、通过top命令定位异常进程(pid)。

        2、通过top -H -p pid命令查看异常进程下,线程CPU使用率情况。

        3、通过jstack pid > log.txt命令,将线程的堆栈信息打印到log.txt文件中。

        4、通过cat log.txt | grep tid(thread id) -A 20命令,过滤出异常线程的相关信息。

        5、通过jstat -gcutil pid 2000 10命令,查看堆内存使用情况。

        6、通过jmap -histo pid命令,查看占用内存资源较多的类对象有哪些。

        基本上到了第6步你就可以知道哪些类对象导致了内存溢出,再去review代码修改bug即可。

  • 22
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值