如果流没有手动关闭,它啥时候关闭?
Posted
技术标签:
【中文标题】如果流没有手动关闭,它啥时候关闭?【英文标题】:When does a stream close if its not closed manually?如果流没有手动关闭,它什么时候关闭? 【发布时间】:2016-01-21 10:09:33 【问题描述】:如果流没有手动关闭,我想知道它什么时候关闭。我的意思是,如果它的引用范围不再是流,它会被关闭吗?
考虑以下示例场景。
Class A
InputStream in;
OutputStream out;
A()
// Initialize and create the streams.
...
Class B
public void myMethod()
A a = new A();
System.out.println("End of my method.")
...
在这里,一旦我完成了流,我将退出myMethod()
,但反过来该进程的程序不会终止并继续进行其他操作。
我没有关闭流。一旦对 A 类的引用范围结束,它会自动关闭吗? (即myMethod()
何时结束)? GC 会处理这个问题吗?另外,我读到一旦进程结束,流将被关闭,系统会释放为它保留的所有资源以供其他进程使用。我们如何检查流是否打开?是否有任何来自 Java 的 linux 命令或选项来检查?
感谢任何帮助!
【问题讨论】:
作为一项规则,您应该始终关闭finally
块(或 try-with-resources)中的所有流(以及一般的 Closeables)
此时,我坐在椅子上,试图记住我打开的所有 Java 流,并假设它们自动关闭了范围。过去 15 年。然后,我站起来大喊“C++ 我非常爱你”。
【参考方案1】:
我不认为 JVM 规范对此做出任何保证。你真的应该finally
关闭这些资源。
当进程结束时,操作系统将释放与其相关的所有资源(包括内存、文件句柄和网络套接字)。
有一些操作系统工具可以检查打开的文件和流,例如lsof
。
【讨论】:
是的,我将在finally
块中关闭它,但出于好奇而询问。但是你不认为 GC 也应该被配置来处理这个问题吗?因为,一旦引用的范围结束,它所引用的所有流以及内存都应该被垃圾回收。不是吗?
是的,GC 最终会发生。但不能保证及时,也不能完全保证运行终结器(这会关闭流)。立场是开发人员应该照顾它。【参考方案2】:
在FileInputStream
的情况下,有一个finalize()
方法可以在流被垃圾回收时释放资源。
并不是说您可以或应该依赖它。这正是FileInputStream
所做的。另一方面,SocketInputStream
覆盖 finalize()
以显式不执行任何操作,依靠 Socket
关闭资源(并且 Socket
没有 finalize()
方法)。
【讨论】:
【参考方案3】:如果您不手动关闭它,那么当进程终止时,所有非托管资源都将被释放,但这不是推荐或最佳实践。完成后,您应该始终关闭流。
管理流的更好且建议的方法是使用 try with resource 选项,如下所示:
try (InputStream input = new FileInputStream(...);
Reader reader = new InputStreamReader(input, ...))
...
我没有关闭流。会不会自动关闭 对A类的引用范围结束了吗?
不,它不会自动关闭。
一个很好的参考是:
Better Resource Management with Java SE 7: Beyond Syntactic Sugar
【讨论】:
【参考方案4】:不保证只要 JVM 正在运行,资源就会被关闭,您建议的实现非常危险。
我的建议。 将 A 类设为 Closeable 并使用 Java 的 tryResourceClose-Statement。 例子在这里。 https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
离开 try-block 后,您就有机会关闭资源。
流本身通常不知道它是否打开。 但是,您自己的 A 类可以跟踪流是否关闭。
【讨论】:
【参考方案5】:这是一种糟糕的编程习惯,是程序员的错误。根据底层数据源,它可能永远不会关闭并且您可能会发生泄漏。您必须在完成后关闭任何资源,在 finally
块中,或者在 Java 7 或更高版本中使用资源尝试,以确保即使抛出异常也将其关闭。
InputStream in;
OutputStream out;
try
// Do your stuff with the streams
finally
if (in != null)
in.close();
if (out != null)
out.close();
【讨论】:
【参考方案6】:使用 Java 7,您可以在 try 语句中创建一个或多个“资源”。 “资源”是实现 java.lang.AutoCloseable 接口的东西。该资源将自动关闭并结束 try 块。
您可以查看this 和java doc 了解更多信息
private static void printFileJava7() throws IOException
try(FileInputStream input = new FileInputStream("file.txt"))
int data = input.read();
while(data != -1)
System.out.print((char) data);
data = input.read();
当 try 块完成时,FileInputStream 将自动关闭。这是可能的,因为 FileInputStream 实现了 Java 接口 java.lang.AutoCloseable。所有实现此接口的类都可以在 try-with-resources 构造中使用。
【讨论】:
以上是关于如果流没有手动关闭,它啥时候关闭?的主要内容,如果未能解决你的问题,请参考以下文章
面试官:IO 操作必须要手动关闭吗?关闭流方法是不是有顺序?
Perl Apache 脚本按预期从 browser-perfroms 运行关闭正在运行的 perl 实例,但是当尝试启动新的 perl 实例时它啥也不做