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

发布时间:2023年12月22日

步骤:

? ? ? ? (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即可。

文章来源:https://blog.csdn.net/Annancqxxx/article/details/135104562
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。