即使InputStream应该保持打开状态,我也需要关闭InputStreamReader吗?

时间:2019-04-06 12:52:05

标签: java memory memory-management bufferedreader inputstreamreader

InputStream作为参数从某个地方传递,在那里将被进一步处理然后关闭。因此,我不想在这里关闭InputStream。考虑以下代码:

void readInputStream(final InputStream inputStream) {
    final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
    String line;
    while ((line = bufferedReader.readLine() != null) {
        // do my thing
    }
}

根据另一Stackoverflow帖子,如果我关闭BufferedReader和/或InputStreamReader,则基础InputStream也将关闭。

我的问题:即使底层的InputStream在其他地方关闭,读者也需要关闭吗?我可以通过不关闭阅读器来获取内存泄漏吗?

2 个答案:

答案 0 :(得分:4)

  

即使底层的InputStream在其他地方已经关闭,读者也需要关闭吗?

不,在这种情况下,他们绝对不需要。但无论如何,将它们关闭通常是一个好主意。

  

是否可以通过不关闭阅读器来导致内存泄漏?

否,假设Reader本身一旦完成就无法访问,就没有内存泄漏。此外,Reader通常不会占用大量内存。

更重要的问题是,是否可以通过不关闭Reader来获得资源泄漏。答案是……取决于。

  • 如果您可以保证基础InputStream始终会在应用程序中的其他位置关闭,那么 可以解决可能的内存泄漏。

  • 如果不能保证,则存在资源泄漏的风险。底层操作系统级别的文件描述符是(例如)Linux中的有限资源。如果JVM无法关闭它们,它们将耗尽,并且某些系统调用将意外失败。

但是如果您执行关闭Reader,则基础InputStream 将被关闭。

close()上多次调用InputStream是无害的,而且几乎不花任何费用。

唯一关闭Reader的情况是关闭基础InputStream是错误的。例如,如果关闭SocketInputStream,则该应用程序的其余部分可能无法重新建立网络连接。同样,与InputStream关联的System.in通常无法重新打开。

在这种情况下,实际上可以安全地对在方法中创建的Reader进行垃圾回收。与InputStream不同,典型的Reader类不会覆盖Object::finalize()来关闭其数据源。


@Pshemo提出了有关系统设计的重要观点。

如果您接受InputStream作为参数,那么用本地Reader ...(尤其是BufferedReader)包装它可能是错误的。 `BufferedReader易于在流上预读。如果流将由调用方之后使用,则您的方法将返回,那么任何已读入缓冲区但未被此方法使用的数据都可能会丢失。

一个更好的主意是呼叫者传递一个Reader。另外,此方法应记录为InputStream的“拥有所有权”。在这种情况下,应该始终close()

答案 1 :(得分:1)

是的,读者需要关闭。使用代理,例如CloseShieldInputStream,以防止关闭传递的参数。

html %>% xml2::read_html() %>% html_nodes(xpath = safe_xpath(target))
#> {xml_nodeset (1)}
#> [1] <div>Fat"her's son</div>

JIC :类似于输入屏蔽,Apache Commons I / O还提供了输出屏蔽来解决类似的问题,即关闭包装输出流-CloseShieldOutputStream


有关更详细的注意事项,请参阅原始答案。归功于@ stephen-c