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