JVM调优实战场景- 内存溢出和死锁
大约 4 分钟
内存溢出的定位与分析
模拟内存溢出
package leetcode.editor.cn.doc;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* <p>
*
* </p>
*
* @author huangKeMing
* @since 2025/4/28
*/
public class TestJvmOutOfMemory {
public static void main(String[] args) {
List<Object> list = new ArrayList<>();
for (int i = 0; i < 10000000; i++) {
String str = "";
for (int j = 0; j < 1000; j++) {
str += UUID.randomUUID().toString();
}
list.add(str);
}
System.out.println("ok");
}
}

运行测试


MAT插件下载
下载后解压运行 MemoryAnalyzer.exe

使用MAT分析报告

根据报告分析,数组对象Oject[] 占用的80%的内存信息,还提示出现代码问题的地方。
查看 Details 详情

可以看到集合中存储的数据,存储了大量的UUID字符串。
************
package com.ke.middleware.test;
/**
* <p>
*
* </p>
*
* @author huangKeMing
* @since 2025/4/28
*/
public class TestDeadLock {
private static Object obj1 = new Object();
private static Object obj2 = new Object();
public static void main(String[] args) {
new Thread(new Thread1()).start();//启动线程01
new Thread(new Thread2()).start();//启动线程02
}
//线程01
private static class Thread1 implements Runnable {
@Override
public void run() {
synchronized (obj1) {
System.out.println("Thread1 拿到了 obj1 的锁!");
try {
// 停顿2秒的意义在于,让Thread2线程拿到obj2的锁
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();}
synchronized (obj2) {
System.out.println("Thread1 拿到了 obj2 的锁!");
}
}
}
}
//线程02
private static class Thread2 implements Runnable {
@Override
public void run() {
synchronized (obj2) {
System.out.println("Thread2 拿到了 obj2 的锁!");
try {
// 停顿2秒的意义在于,让Thread1线程拿到obj1的锁
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj1) {
System.out.println("Thread2 拿到了 obj1 的锁!");
}
}
}
}
}
在win下查看死锁
## 查看所有java进程
tasklist | findstr java
## 查看某一java进程的堆栈信息
jstack 15616
在Linux系统下
程序启动运行之后,使用jps查找java进行。 jstack打印堆栈信息

jstack 18487 | grep 'BLOCKED' -A 15 --color 1

可以清楚的看到,两个线程相互等待持有的锁。是造成死锁的原因
使用Arthas进行分析
thread -b

可以精确定位到出现死锁问题的代码。相比使用命令操作省去了很多步骤,直接可以打印线程信息。