You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何编写的Java未关闭资源代码无内存泄漏?求演示用泄漏代码

为什么循环创建未关闭的FileInputStream没出现内存泄漏?

核心原因有两点:

  • Finalizer自动回收机制:FileInputStream继承自InputStream,这类IO流子类大多重写了finalize()方法,当对象被GC标记为垃圾时,JVM的Finalizer线程会自动调用close()释放底层文件描述符和关联资源。
  • 局部变量的生命周期:如果你的代码里FileInputStream是循环内的局部变量,每次循环结束后该变量就失去引用,会被GC及时回收,Finalizer随之执行资源释放,不会造成资源堆积。

另外,FileInputStream本身在堆内存中占用空间极小,即使短暂未被回收,内存增长也不明显,普通监控可能难以捕捉到临时波动。

如何修改代码产生可观测的内存泄漏?

制造内存泄漏的关键是阻止GC回收FileInputStream对象,让Finalizer无法触发资源释放。最直接的方式是用全局容器持有所有创建的流实例,保持强引用。

原无泄漏代码示例

public class NoLeakDemo {
    public static void main(String[] args) throws Exception {
        while (true) {
            // 局部变量,循环后失去引用,会被GC回收
            FileInputStream fis = new FileInputStream("test.txt");
            Thread.sleep(10);
        }
    }
}

修改后的泄漏代码示例

import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;

public class LeakDemo {
    // 全局静态集合,持续持有流实例的强引用
    private static List<FileInputStream> leakedStreams = new ArrayList<>();

    public static void main(String[] args) throws Exception {
        while (true) {
            FileInputStream fis = new FileInputStream("test.txt");
            leakedStreams.add(fis); // 将流加入集合,阻止GC回收
            Thread.sleep(10);
            // 打印当前泄漏的流数量,便于观察
            System.out.println("当前泄漏的流数量: " + leakedStreams.size());
        }
    }
}

泄漏验证

运行这段代码后,用性能分析工具(如VisualVM、JProfiler)可观测到:

  • 堆内存占用持续上升,FileInputStream实例数量不断增加
  • 操作系统层面的文件描述符数量持续增长(可通过lsof -p <进程ID>或jstat命令查看)
  • 最终会触发OOM(内存溢出)或达到系统文件描述符上限抛出异常

内容的提问来源于stack exchange,提问作者shabanovve

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 21:42:15