• JVM内存泄漏分析的demo


    本文参考:

    JVM调优参数、方法、工具以及案例总结

    JVM监控和调优常用命令工具总结 - Pickle - 博客园 (cnblogs.com)

    面试官问我JVM调优,我忍不住了! - Java3y - 博客园 (cnblogs.com)

    从实际案例聊聊Java应用的GC优化 (qq.com)

    JVM调优的几种场景(建议收藏) (qq.com)

    上面是在学习过程中参考到的各种文献,下面是动手去做一个内存泄漏分析的小demo

    场景模拟

    1. 编写一个会有内存泄漏的场景,在下面我是模拟了一个线程池不销毁并且不停创建非核心线程(非核心线程在60s不用就会自动destory)的例子
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    /**
     * @Author jiangxuzhao
     * @Description
     * @Date 2023/9/17
     */
    public class MemoryLeak {
        public static void main(String[] args) {
            MemoryLeak memoryLeak = new MemoryLeak();
            while (true) {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                memoryLeak.run();
            }
        }
    
        private void run() {
            // 不断创造非核心线程
            ExecutorService executorService = Executors.newCachedThreadPool();
            for (int i = 0; i < 10; i++) {
                executorService.submit(()->{
    //                System.out.println(Thread.currentThread().getName());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                });
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    1. 命令行操作,编译文件

      javac MemoryLeak.java   
      
      • 1
    2. 命令行操作,执行文件,并且-Xms1m -Xmx1m表示运行的初始堆大小1m,最大堆大小也是1m,这些参数较小是为了有意构造OOM场景,-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./heap.bin是为了能够dump出OOM日志

      java -Xms1m -Xmx1m -XX:+PrintGC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./heap.bin MemoryLeak
      
      • 1

      注意⚠️:dump文件太大,一下子不能够产生heap.bin文件,需要重试或者耐心等待

    3. 观察输出

      ...
      [Full GC (Ergonomics)  997K->997K(1536K), 0.0150748 secs]
              at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:674)
      [Full GC (Ergonomics)  997K->992K(1536K), 0.0153944 secs]
              at java.lang.StringBuilder.append(StringBuilder.java:214)
              at java.util.concurrent.Executors$DefaultThreadFactory.newThread(Executors.java:613)
              at java.util.concurrent.ThreadPoolExecutor$Worker.(ThreadPoolExecutor.java:619)
      [Full GC (Ergonomics)  997K->992K(1536K), 0.0156156 secs]
              at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:932)
              at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1378)
              at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
              at MemoryLeak.run(MemoryLeak.java:26)
              at MemoryLeak.main(MemoryLeak.java:18)
      [Full GC (Ergonomics)  997K->989K(1536K), 0.0149037 secs]
      [Full GC (Ergonomics)  997K->989K(1536K), 0.0146840 secs]
      [Full GC (Ergonomics)  997K->989K(1536K), 0.0138023 secs]
      [Full GC (Ergonomics)  997K->989K(1536K), 0.0146598 secs]
      [Full GC (Ergonomics)  997K->989K(1536K), 0.0140917 secs]
      [Full GC (Ergonomics)  997K->989K(1536K), 0.0141075 secs]
      [Full GC (Ergonomics)  997K->990K(1536K), 0.0138773 secs]
      [Full GC (Ergonomics)  997K->990K(1536K), 0.0137902 secs]
      [Full GC (Ergonomics)  997K->990K(1536K), 0.0134941 secs]
      [Full GC (Ergonomics)  997K->990K(1536K), 0.0139297 secs]
      [Full GC (Ergonomics)  997K->990K(1536K), 0.0138875 secs]
      [Full GC (Ergonomics)  997K->990K(1536K), 0.0136721 secs]
      [Full GC (Ergonomics)  997K->990K(1536K), 0.0135201 secs]
      [Full GC (Ergonomics)  997K->991K(1536K), 0.0138388 secs]
      ...
      [Full GC (Ergonomics)  997K->995K(1536K), 0.0135345 secs]
      [Full GC (Ergonomics)  997K->995K(1536K), 0.0135026 secs]
      [Full GC (Ergonomics)  997K->995K(1536K), 0.0130507 secs]
      [Full GC (Ergonomics)  997K->995K(1536K), 0.0128278 secs]
      [Full GC (Ergonomics)  997K->996K(1536K), 0.0138620 secs]
      [Full GC (Ergonomics)  997K->996K(1536K), 0.0129367 secs]
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34

      打印出了Full GC的过程,但是占用的内存还是越来越多,确实发生了内存泄漏,初步猜测就是线程创建后一直没有销毁,线程池也没有shutdown

    问题分析

    借助MAT分析上面dump下来的heap.bin文件

    去官网下载就好 -> https://eclipse.dev/mat/downloads.php

    1. File->Open Heap Dump… 查看刚刚的heap.bin文件

    在这里插入图片描述

    1. 选择其中的泄漏报告 Leak Suspects
      在这里插入图片描述

    可以看到Problem Suspect 1 2 3列出了几个可能发生内存泄漏的对象,从1和3可以看出,竟然有1435个Thread对象以及144个ThreadPoolExecutor对象,确实占有了大量内存。

    结论也可以得出来:

    每个ThreadPoolExecutor创建了10个线程,每个线程的在不处理任务后的60s会被回收,线程池此时也会一直存在等待接受新的任务。又由于外部一直在while(true)创建新的线程池,导致这一分钟以内,堆积了大量被创建的线程池以及其创建的线程。

  • 相关阅读:
    get(obj, “a.b[0].c“, 0)
    Linux桌面环境中应用程序无法启动图形交互界面
    Flink之Watermark
    实时车辆行人多目标检测与跟踪系统(含UI界面,Python代码)
    vue 实现图片以鼠标为中心放大,并可以随意在div内拖动
    macos 上彻底卸载 DevEco Studio
    Python-NumPy系统教程
    ES6 Class和Class继承
    上传代码到GitHub仓库
    Python从入门到入土-基本技能
  • 原文地址:https://blog.csdn.net/qq_44036439/article/details/132958043