Java导致内存泄漏的多种情况分析

 更新时间:2026年01月09日 08:49:33   作者:烟沙九洲  
本文介绍了Java中常见的内存泄漏情况,包括生命周期长的集合、未关闭的资源连接、ThreadLocal使用不当、内部类与外部类引用非静态内部类、监听器与回调注册后没有注销,推荐使用MAT和VisualVM等工具进行内存泄漏排查,感兴趣的朋友跟随小编一起看看吧

今天我们来一起聊一聊有哪些情况会导致内存泄漏。

什么是 内存泄漏 呢?

内存泄漏 是指对象 已经不再被程序使用,但因为某些原因 无法被垃圾回收器回收,长期占用内存,最终可能引发 OOM(OutOfMemoryError)。

接下来我们看一下常见的几类内存泄漏场景。

1、生命周期长的集合

将对象放入 静态 或 生命周期很长 的集合(如 public static List<Object> list = new ArrayList<>();),即使后面不再需要,集合仍持有其引用,导致无法GC

2、未关闭的资源

连接、流等资源未调用 close() 方法关闭。这些资源不仅占用内存,还可能占用文件句柄(操作系统分配的唯一标识,凭它,你才能操作文件资源)、网络连接等系统资源。比如 数据库连接、文件流(FileInputStream)、Socket连接 等。

public class FileTest {
    public static void main(String[] args) {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("test.txt");
            // 读取文件,未调用 fis.close()
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            // 未调用 fis.close() → fis 持有 Native 引用,无法回收
        }
    }
}

3、ThreadLocal 使用不当

将对象存入 ThreadLocal 后,未在后续调用 remove() 清理。若线程来自线程池(会复用),其 ThreadLocalMap 中的值会一直存活。

public class ThreadLocalTest {
    private static ThreadLocal<User> userThreadLocal = new ThreadLocal<>();
    public static void main(String[] args) {
        // 线程池(核心线程长期存活)
        TThreadPoolExecutor executor = new ThreadPoolExecutor(
                2,
                4,
                10,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(100),
                new ThreadFactoryBuilder().setNameFormat("my-thread-pool-%d").setDaemon(false).setPriority(Thread.NORM_PRIORITY).build(),
                new ThreadPoolExecutor.AbortPolicy()
        );
        executor.submit(() -> {
            User user = new User("李四", 30);
            userThreadLocal.set(user); // 存储到 ThreadLocal
            // 业务执行完毕,未调用 remove()
            // 核心线程不会销毁,ThreadLocal 仍持有 user 引用
        });
    }
}

ps:未进行 remove(),还可能会导致 ThreadLocal 取值串门。

4、内部类与外部类引用

非静态内部类(或匿名类)会 隐式持有 外部类的引用。如果内部类实例生命周期更长(如被缓存或另一个线程引用),会阻止外部类被回收。

public class OuterClass {
    private byte[] bigData = new byte[1024 * 1024 * 10]; // 10MB 大对象
    // 非静态内部类
    class InnerClass {
        // 内部类隐式持有 OuterClass 引用
    }
    public InnerClass createInner() {
        return new InnerClass();
    }
    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        InnerClass inner = outer.createInner();
        // 置空外部类引用,但 inner 仍持有 outer 引用
        outer = null;
        // 若 inner 被静态变量/线程长期持有 → outer 对象(含 bigData)无法回收
    }
}

5、 监听器与回调

注册了 监听器 或 回调 后,在对象不再需要时 没有注销,导致源对象仍持有监听器的引用(比如 事件监听器、消息队列的消费者等)。

排查工具推荐

  • MAT(Memory Analyzer Tool):分析堆 Dump 文件,定位泄漏对象、引用链(谁在持有泄漏对象);
  • VisualVM:JDK 自带工具,监控内存占用趋势,生成堆 Dump,简单排查泄漏。

这里我只列了常见的几种情况,欢迎大家补充其他内存泄漏场景。

到此这篇关于Java导致内存泄漏的多种情况分析的文章就介绍到这了,更多相关java内存泄漏内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java中字符串根据宽度(像素)换行的问题

    Java中字符串根据宽度(像素)换行的问题

    这篇文章主要介绍了Java中字符串根据宽度(像素)换行的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • Java中的JVM虚拟机内存分配详解

    Java中的JVM虚拟机内存分配详解

    这篇文章主要介绍了Java中的JVM虚拟机内存分配详解,虚拟机是一种能够执行 Java 字节码的虚拟机,它是 Java 语言的核心组成部分,负责将 Java 代码转换为机器码并执行,JVM 提供了内存管理、垃圾回收、线程管理等功能,需要的朋友可以参考下
    2023-10-10
  • Apache Ignite 与 Spring Boot 集成详细指南

    Apache Ignite 与 Spring Boot 集成详细指南

    Apache Ignite官方指南详解如何通过Spring Boot Starter扩展实现自动配置,支持厚/轻客户端模式,简化Ignite节点和客户端的部署与管理,提升开发效率和可维护性,接下来通过本文介绍Apache Ignite与Spring Boot 集成详细指南,感兴趣的朋友一起看看吧
    2025-07-07
  • Java单元测试Powermockito和Mockito使用总结

    Java单元测试Powermockito和Mockito使用总结

    公司单元测试框架选用了Junit 4.12,Mock框架选用了Mockito和PowerMock,本文主要介绍了Java单元测试Powermockito和Mockito使用总结,感兴趣的可以了解一下
    2021-09-09
  • IDEA自定义pom依赖的步骤详解

    IDEA自定义pom依赖的步骤详解

    这篇文章主要介绍了IDEA自定义pom依赖的步骤详解,本文分步骤通过图文并茂的形式给大家介绍的非常详细对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-04-04
  • JavaEE中volatile、wait和notify详解

    JavaEE中volatile、wait和notify详解

    这篇文章主要给大家介绍了关于JavaEE中volatile、wait和notify的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2023-02-02
  • SpringData Redis的具体使用

    SpringData Redis的具体使用

    本文主要介绍了SpringData Redis的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-04-04
  • Java基础教程之包(package)

    Java基础教程之包(package)

    这篇文章主要介绍了Java基础教程之包(package),本文详细讲解了包的创建、使用等方法,需要的朋友可以参考下
    2014-08-08
  • JSR303校验前端传递的数据方式

    JSR303校验前端传递的数据方式

    这篇文章主要介绍了JSR303校验前端传递的数据方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • Spring JPA之find拓展方法示例详解

    Spring JPA之find拓展方法示例详解

    这篇文章主要为大家介绍了Spring JPA之find拓展方法示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-04-04

最新评论