unclosed流是否导致java中的内存泄漏?

时间:2014-04-06 01:50:20

标签: java memory-management memory-leaks

我认为开放流会导致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流,是否会导致内存泄漏?

3 个答案:

答案 0 :(得分:31)

准确地使用术语“内存泄漏”这一点非常重要。关于Java。

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

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

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

答案 1 :(得分:5)

  

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

任何版本的Java,就此而言,任何语言都有这个问题;它不是特定于Java。

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

Java Closeable表示您拥有的实例可能或可能不,拥有系统资源;但如果它不这样做,如果你不.close()它,你就会泄漏资源;它很简单。

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

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

使用Java 6,您将要使用Guava的Closer,因为这是关闭所有资源的最安全的方法(并且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,您可以尝试使用所有AutoCloseable资源(Closeable扩展)的资源:

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

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

但又一次:不要冒险。关闭它们。

答案 2 :(得分:0)

答案取决于流。

内存泄漏只是一种情况,你可以保留你并不打算做的事情。这总是由于编程错误:某个地方某人忘记释放("从所有强引用中删除")某些实例。随着时间的推移,这些加起来,然后你注意到"泄漏"。缓存无限增长就是一个很好的例子。

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

在您的示例中,ByteArrayInputStream.close()方法不执行任何操作,因此没有任何问题。 BufferedInputStream.close()只是将调用委托给包装类,所以在这种情况下,再次没有问题。

处理文件的更复杂的流,如果没有关闭,网络流可能会造成泄漏,但这种情况并不常见。我假设流本身没有保留,但可以收集。在许多情况下," smart"流甚至可以在自己的集合中修复这些疏忽,并自行执行必要的清理(这仍然是流应该在某处清楚地记录/通知的异常情况)。