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

未关闭的流是否会导致java内存泄漏?,java,memory-management,memory-leaks,Java,Memory Management,Memory Leaks,我相信开放流会导致java中的内存泄漏(至少Java1.6和更早版本确实存在这个问题) 但是,在搜索时(即使在这里),我发现一些人同意这一点,而其他人则不同意。所以,如果我写这个程序: import java.io.*; public class CreatingMemoryLeak { public static void main(String args[]) { String s = "xxxxxxx"; InputStream in =

我相信开放流会导致java中的内存泄漏(至少Java1.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
流,它会导致内存泄漏吗

(至少Java1.6和更早版本有这个问题)

任何版本的Java,任何语言都有这个问题;它不是Java特有的

如果您获得了需要系统资源的输入或输出句柄,则无论发生什么情况,都需要释放它们

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

例如,您可能有一个将
InputStream
作为参数的方法;好的,很好,但是这是什么
InputStream
?它是一个
FileInputStream
还是一个
ByteArrayInputStream
,甚至是其他什么东西?你不可能知道。第一个需要正确关闭,但第二个不需要

那又怎样
.close()
不管怎样,你没有什么可失去的。你真的想冒险吗

使用Java 6时,您会希望使用Guava,因为这是关闭所有资源的最安全的方法(JDK不提供这样的工具):

使用Java 7,您可以尝试使用可与所有
AutoCloseable
资源(可
Closeable
扩展)一起使用的资源:

Closer
和try-with-resources之间的主要区别在于,对于后者,资源将在
catch
之前关闭,而
Closer
将在
最后关闭


但再次强调:不要冒险。关闭它们。

对于Java来说,精确使用“内存泄漏”一词很重要

在Java中,当代码永久保存引用时,就会发生内存泄漏,因此某些对象永远不会被垃圾收集

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


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

答案取决于流

内存泄漏只是一种情况,即您保留了一些您不打算保留的内容。这总是由于编程错误:某个地方的某个人忘记释放(从所有强引用中分离)某些实例。随着时间的推移,这些累积在一起,然后你会注意到“泄漏”。无限增长的缓存就是一个很好的例子

例如,流一旦打开/使用,就可以将一些数据放入共享容器(通常是静态的),如资源锁、某种缓存等。然后在close方法中清理这个资源。因此跳过最后一部分会造成内存泄漏

在您的示例中,该方法不执行任何操作,因此没有问题。只需将调用委托给包装类,因此在本例中,同样没有问题


更复杂的流处理文件,网络流可以创建泄漏,如果不关闭,但它不是常见的。我假设流本身没有被保留,而是可以被收集。在许多情况下,“智能”流甚至可能在其自己的收集过程中修复这些疏忽,并自行执行必要的清理(这仍然是一种异常情况,流应该在某个地方清楚地记录/通知)。

请注意,
关闭的想法通常是释放本机资源(例如C堆分配的数据需要
delete
d)。用于
ByteArrayInputStream
的文档。因此,我认为这不是您在这里实际询问的一个好例子。
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
}
try (
    final InputStream in = ...;
    // etc
) {
    // work with AutoCloseable resources
} catch (WhateverException e) {
    // deal with e, rethrow if necessary
}