如果流没有手动关闭,它啥时候关闭?

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 操作必须要手动关闭吗?关闭流方法是不是有顺序?

java程序中的流都要统统关闭吗?有没有先后顺序??

Java中,static代码块创建的IO流需要手动关闭吗?

Perl Apache 脚本按预期从 browser-perfroms 运行关闭正在运行的 perl 实例,但是当尝试启动新的 perl 实例时它啥也不做

java中IO流操作怎样关闭流

面试官:IO 操作必须要手动关闭吗?关闭流方法是否有顺序?