JVM 内存溢出和死锁检测

内存溢出案例

案例环境

案例代码

bash 复制代码
package com.hero.jvm.memory;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
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");
 }
}

JVM 参数

  1. 让案例尽快 OOM
  2. 开启发生 OOM 时自动 dump 堆快照
bash 复制代码
#参数如下:
-Xms8m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError

执行结果

溢出打印

bash 复制代码
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid31092.hprof ...
Heap dump file created [8453096 bytes in 0.031 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3332)
at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:448)
at java.lang.StringBuilder.append(StringBuilder.java:136)
at com.hero.TestJvmOutOfMemory.main(TestJvmOutOfMemory.java:13)

dump 了堆快照文件

导入 MAT 分析

可以看到,有81.72%的内存由Object[]数组占有,所以比较可疑。

分析:这个可疑是正确的,因为已经有超过80%的内存都被它占有,这是非常有可能出现内存溢出的。

直接看对象详情

死锁检测

如果在生产环境发生了死锁,我们将看到的是部署的程序没有任何反应了,这个时候我们可以借助jstack进行分析,下面我们实战下查找死锁的原因。

案例环境

java 复制代码
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 的锁!");
                }
            }
        }
    }
}

使用 Jstack 分析

命令:jstack 18487 | grep 'BLOCKED' -A 15 --color

发现两个互相等待锁的线程

使用 Arthas 分析死锁

thread-b 命令

相关推荐
没有bug.的程序员10 小时前
Kubernetes 与微服务的融合架构:调度、弹性、健康检查深度协同
jvm·微服务·云原生·架构·kubernetes·健康检查·弹性伸缩
Chan1620 小时前
【 Java八股文面试 | JavaSE篇 】
java·jvm·spring boot·面试·java-ee·八股
-西门吹雪1 天前
c++线程之std::async浅析
java·jvm·c++
alonewolf_991 天前
深入解析G1与ZGC垃圾收集器:原理、调优与选型指南
java·jvm·算法
alonewolf_991 天前
JVM内存模型深度剖析与调优实战:从理论到实践,全面掌握JVM内存管理
jvm
alonewolf_991 天前
JVM对象创建与内存分配机制深度剖析:从创建到回收的全流程解析
jvm
sunywz1 天前
【JVM】(4)JVM对象创建与内存分配机制深度剖析
开发语言·jvm·python
这周也會开心1 天前
JVM-类加载子系统
jvm
xxxmine1 天前
JVM 双亲委派模型
jvm