一 内存泄漏导致OOM

1 编写内存溢出对的代码

package com.study.heap;

import java.util.ArrayList;
import java.util.List;

/**
 * 测试排查内存溢出的的解决方案
 *
 * @author zhangpba
 * @date 2021-11-01
 */
public class HeapOOM {

    private int heapObjectNum;

    public HeapOOM(int heapObjectNum) {
        this.heapObjectNum = heapObjectNum;
    }

    public static void main(String[] args) throws Exception{
        List<HeapOOM> list = new ArrayList<>();
        // 不断往集合中放入元素,让其内存溢出
        int i = 0;
        while (true){
            Thread.sleep(1);
            System.out.println(i++);
            list.add(new HeapOOM(i));
        }
    }
}

2 配置启动参数

在idea中的Edit Configuration的VM Options中添加如下参数
-verbose:gc -Xms20m -Xmn10m -Xmx20m -XX:+PrintGCDetails -XX:SurvivorRatio=8
OOM定位_内存溢出

-verbose:gc:控制台输出GC日志
-Xms:初始内存大小(memory size)
-Xmn:最小内存
-Xmx:最大内存
-XX:+PrintGCDetails:控制台输出GC具体日志信息
-XX:SurvivorRatio=8:Eden区占比,新生代分为Eden区和Survivor区(from/to Survivor),SurvivorRatio参数定义了Eden、Survivor的比例,默认为8,也就是Eden占新生代的8/10

3 启动测试代码,观察内存中的变化

启动后代码报异常:java.lang.OutOfMemoryError: Java heap space

OOM定位_线程死锁_02

本地通过visualVM来观察内存中的变化,或者用jmap -heap pid来查看老年代,Eden和s0,s1区域内存占用的情况变化

 3.1 visualVM来观察到的变化:

堆中的变化:

OOM定位_内存溢出_03

 

OOM定位_java_04

在visualVM中,很容易看到锁执行的进程号为:10336

 3.2 用jmap -heap pid查看的情况

 OOM定位_java_05

4 查看最耗内存的对象:jmap -histo:live pid| more

OOM定位_死锁_06

分析出我们写的测试类HeapOOM所创建的对象是导致内存溢出的罪魁祸首。然后针对这个类所涉及的代码进行优化(首先需要对JVM参数进行优化)。

5.OOM优化

二 线程死锁导致OOM

1. 实例代码

package com.study.heap;

/**
 * 死锁线程
 *
 * @author zhangpba
 * @date 2021-11-01
 */
public class DeadLock {

    private Object lockA = new Object();
    private Object lockB = new Object();

    private void deadLock() {
        // 定义线程t1,锁定A变量睡眠2秒去抢占B的资源
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("进入线程t1");
                synchronized (lockA) {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (lockB) {
                        System.out.println(Thread.currentThread().getName());
                    }
                }
            }
        }, "thread-zhangpba-1");

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("进入线程t2");
                synchronized (lockB) {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (lockA) {
                        System.out.println("线程名:" + Thread.currentThread().getName());
                    }
                }
            }
        }, "thread-zhangpba-1");

        t1.start();
        t2.start();
    }

    public static void main(String[] args) {
        new DeadLock().deadLock();
    }
}

2.通过visualVM排查线程死锁问题

无死锁

OOM定位_ide_07

 有死锁:会在上面显示红色字体:检测到死锁!生成一个线程 Dump 以获取更多信息

OOM定位_内存溢出_08

点击线程Dump,可以考到详细死锁信息:

OOM定位_内存溢出_09