即使 InputStream 应该保持打开状态,我是否需要关闭 InputStreamReader?
Do I need to close InputStreamReader even if InputStream should remain open?
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
}
}
如果我关闭 BufferedReader
and/or InputStreamReader
,那么基础 InputStream
也将被关闭,根据另一个 Whosebug post。
我的问题:Readers 是否需要关闭,即使基础 InputStream
在其他地方关闭?不关闭 Readers 会导致内存泄漏吗?
Do readers need to be closed, even if the underlying InputStream
is closed somewhere else?
不,他们绝对不需要在那种情况下。但无论如何关闭它们通常是个好主意。
Can I get a memory leak by not closing readers?
不,没有内存泄漏,假设 Reader
本身在您完成后变得无法访问。此外,Reader
通常不会占用大量内存。
更重要的问题是您是否可以通过不关闭 Reader
来获得 资源 泄漏。答案是……视情况而定。
如果您可以保证底层 InputStream
将始终在应用程序的其他地方关闭,那么 that 会处理可能的内存泄漏.
如果不能保证,那么就有资源泄露的风险。底层 OS 级别的文件描述符是(例如)Linux 中的有限资源。如果 JVM 不关闭它们,它们可以 运行 退出并且某些系统调用将开始意外失败。
但是如果您做平仓Reader
那么基础InputStream
将平仓。
在 InputStream
上多次调用 close()
是无害的,几乎不需要任何费用。
您不应该关闭Reader
的唯一情况是关闭基础InputStream
是错误的。例如,如果您关闭 SocketInputStream
应用程序的其余部分可能无法重新建立网络连接。同样,与 System.in
关联的 InputStream
通常无法重新打开。
在这种情况下,允许对您在方法中创建的 Reader
进行垃圾回收实际上是安全的。与 InputStream
不同,典型的 Reader
class 不会覆盖 Object::finalize()
以关闭其数据源。
@Pshemo 提出了一个关于系统设计的重要观点。
如果您接受 InputStream
作为参数,那么用本地 Reader
包裹它可能是错误的……尤其是 BufferedReader
。 BufferedReader
易于在流中预读。如果调用者 在 你的方法 returns 之后要使用流,那么任何已读入缓冲区但未被此方法使用的数据都可能是迷路了。
更好的办法是让调用者传递 Reader
。或者,此方法应记录为 取得 InputStream
的所有权。在那种情况下,它 应该 总是 close()
它。
是的,读者需要关闭。使用代理,例如CloseShieldInputStream,防止传入的参数被关闭
void readInputStream(InputStream inputStream) throws IOException{
try (var bufferedReader = new BufferedReader(new InputStreamReader(
new CloseShieldInputStream(inputStream)))) {
String line;
while ((line = bufferedReader.readLine()) != null) {
// do my thing
}
}
}
JIC: 与输入屏蔽类似,Apache Commons I/O 也提供了输出屏蔽来解决与关闭包装输出流类似的问题,- CloseShieldOutputStream
更详细的注意事项请参考原回答。感谢@stephen-c
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
}
}
如果我关闭 BufferedReader
and/or InputStreamReader
,那么基础 InputStream
也将被关闭,根据另一个 Whosebug post。
我的问题:Readers 是否需要关闭,即使基础 InputStream
在其他地方关闭?不关闭 Readers 会导致内存泄漏吗?
Do readers need to be closed, even if the underlying
InputStream
is closed somewhere else?
不,他们绝对不需要在那种情况下。但无论如何关闭它们通常是个好主意。
Can I get a memory leak by not closing readers?
不,没有内存泄漏,假设 Reader
本身在您完成后变得无法访问。此外,Reader
通常不会占用大量内存。
更重要的问题是您是否可以通过不关闭 Reader
来获得 资源 泄漏。答案是……视情况而定。
如果您可以保证底层
InputStream
将始终在应用程序的其他地方关闭,那么 that 会处理可能的内存泄漏.如果不能保证,那么就有资源泄露的风险。底层 OS 级别的文件描述符是(例如)Linux 中的有限资源。如果 JVM 不关闭它们,它们可以 运行 退出并且某些系统调用将开始意外失败。
但是如果您做平仓Reader
那么基础InputStream
将平仓。
在 InputStream
上多次调用 close()
是无害的,几乎不需要任何费用。
您不应该关闭Reader
的唯一情况是关闭基础InputStream
是错误的。例如,如果您关闭 SocketInputStream
应用程序的其余部分可能无法重新建立网络连接。同样,与 System.in
关联的 InputStream
通常无法重新打开。
在这种情况下,允许对您在方法中创建的 Reader
进行垃圾回收实际上是安全的。与 InputStream
不同,典型的 Reader
class 不会覆盖 Object::finalize()
以关闭其数据源。
@Pshemo 提出了一个关于系统设计的重要观点。
如果您接受 InputStream
作为参数,那么用本地 Reader
包裹它可能是错误的……尤其是 BufferedReader
。 BufferedReader
易于在流中预读。如果调用者 在 你的方法 returns 之后要使用流,那么任何已读入缓冲区但未被此方法使用的数据都可能是迷路了。
更好的办法是让调用者传递 Reader
。或者,此方法应记录为 取得 InputStream
的所有权。在那种情况下,它 应该 总是 close()
它。
是的,读者需要关闭。使用代理,例如CloseShieldInputStream,防止传入的参数被关闭
void readInputStream(InputStream inputStream) throws IOException{
try (var bufferedReader = new BufferedReader(new InputStreamReader(
new CloseShieldInputStream(inputStream)))) {
String line;
while ((line = bufferedReader.readLine()) != null) {
// do my thing
}
}
}
JIC: 与输入屏蔽类似,Apache Commons I/O 也提供了输出屏蔽来解决与关闭包装输出流类似的问题,- CloseShieldOutputStream
更详细的注意事项请参考原回答。感谢@stephen-c