未关闭的流是否会导致 Java 中的内存泄漏?

2022-09-02 23:26:03

我相信开放流会导致java中的内存泄漏(至少java 1.6及更早版本确实存在此问题)。

但是,在搜索(甚至在这里)时,我发现有些人同意这一点,而其他人则不同意。所以,如果我写这个程序:

import java.io.*;
public class CreatingMemoryLeak {

    public static void main(String args[])
    {
        String s = "xxxxxxx";
        InputStream in = new ByteArrayInputStream(ss.getBytes());
        BufferedInputStream bf = new BufferedInputStream(in);

        try {
            while(bf.read()>0)
            {
                System.out.println("got it");
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("Here is a input stream " + s +" causing a memory leak");

    }
}

如果我没有显式关闭流,它是否会导致内存泄漏?bf


答案 1

对于Java来说,准确使用术语“内存泄漏”非常重要。

在 Java 中,当您的代码永久保存引用时,会发生内存泄漏,因此永远不会对某些对象进行垃圾回收。

从这个意义上说,未能关闭流不是内存泄漏。具有本机资源的流具有终结器;GC最终将关闭它们。除非您持有对未关闭流的引用,否则它不是泄漏。

但是,除了内存泄漏之外,还有其他种类的泄漏。大多数操作系统限制打开的文件数。如果您未能关闭流,GC可能需要很长时间才能为您关闭它们;最终结果可能是系统文件描述符用完,代码无法再打开一个文件。有些人会称之为泄漏,但将其称为内存泄漏是不准确的。


答案 2

(至少java 1.6及更早版本确实存在此问题)。

任何版本的Java,以及任何语言,都有这个问题。它不是特定于Java的。

如果您掌握了需要系统资源的输入或输出句柄,则无论如何都需要释放它们。

Java必须表明您持有的实例可能持有系统资源,也可能不持有系统资源;但是如果它这样做了,如果你不这样做,你就会泄漏资源;就是这么简单。Closeable.close()

例如,您可能有一个方法,该方法具有作为参数;好吧,好吧,但这是什么?是 a 还是 a ,甚至是其他东西?你无法知道。第一个需要正确关闭,但第二个不需要。InputStreamInputStreamFileInputStreamByteArrayInputStream

那又怎样? 无论如何,他们都没有什么可失去的。你真的想抓住这个机会吗?.close()

在Java 6中,你会想要使用Guava的Close,因为这是关闭所有资源的最安全的方式(JDK不提供这样的工具):

final Closer closer = Closer.create();

try {
    final InputStream in = closer.register(openInHere());
    final InputStream in2 = closer.register(...);
    final OutputStream out = closer.register(...);
    // do work with in, in2, out, other
} catch (WhateverException e) {
    // IF WhateverException is not an IOException and you want to rethrow...
    // throw closer.rethrow(e, WhateverException.class);
} finally {
    closer.close(); // always safe
}

在 Java 7 中,您可以尝试使用资源,它可以处理所有资源(扩展):AutoCloseableCloseable

try (
    final InputStream in = ...;
    // etc
) {
    // work with AutoCloseable resources
} catch (WhateverException e) {
    // deal with e, rethrow if necessary
}

与“试用资源”之间的主要区别在于,对于后者,资源将在 之前关闭,而将在 中关闭它们。ClosercatchCloserfinally

但同样:不要冒险。全部关闭。


推荐