JVM是否自动关闭文件?

在某处我读到没有必要自己关闭它,只需离开它,JVM将帮助你做到这一点。 这是真的吗?

假设我需要从文件中获取数据

Source.fromFile(fileName).getLines() 

直接,没有

 val source = Source.fromFile(fileName) val lines = source.getLines() ............ source.close() 

第一种方式,我无法直接访问源并关闭它。 我的JVM工作了很长时间。 我需要关闭一个文件(需要关闭未使用的资源)。

如果有人可以在这里留下一些链接或解释,那将是很棒的。

在某处我读到没有必要自己关闭它,只需离开它,JVM将帮助你做到这一点。 这是真的吗?

这部分是正确的。

如果你打开一个文件,使用它,然后删除文件或流句柄(或任何你想要调用它),并且GC找到它,然后GC将排队文件句柄对象以进行最终确定。 当完成最终化时,文件处理程序的finalize()方法将释放资源; 即文件描述符。

但是,依靠GC来做这件事是个坏主意

  • 如果可以访问文件句柄,则GC不会完成它。
  • 您可以知道GC何时运行下一个1
  • 当GC运行时,它不一定会收集所有的垃圾2
  • 排队等待最终确定的对象直到GC完成后才能实际完成。 (见@ Holger的评论)

把这四件事放在一起,在GC收集和关闭废弃的文件句柄之前,应用程序很容易用完文件描述符。 如果发生这种情况,您可能会在打开文件,目录,套接字等操作时遇到exception。

以下是您可以运行的示例(在Linux / UNIX上)以查看此情况:

 import java.io.FileInputStream; public class Test { public static void main(String[] args) throws Exception { for (int i = 0; i < 100000; i++) { new FileInputStream("/etc/motd"); } } } $ javac Test.java $ java Test Exception in thread "main" java.io.FileNotFoundException: /etc/motd (Too many open files) at java.io.FileInputStream.open0(Native Method) at java.io.FileInputStream.open(FileInputStream.java:195) at java.io.FileInputStream.(FileInputStream.java:138) at java.io.FileInputStream.(FileInputStream.java:93) at Test.main(Test.java:6) 

1 – 典型的GC仅在堆(或堆的一部分)达到给定的“饱满度”阈值时运行。 如果应用程序未分配许多对象,则可能需要很长时间才能达到阈值。

2 – 现代JVM使用分代垃圾收集器,它以不同的速率收集堆的不同部分。

是的,在某些情况下确实如此, JVM将在一段时间内通过调用finalize方法帮助释放文件描述符(您可以尝试通过System.gc()来validation它)。

并且完全同意我们需要在不需要时显式关闭InputStream并释放文件描述符

但是如果你的应用程序不经常对文件描述符(文件,网络io)进行操作,我们是否也需要关心它? 毕竟,有finalize方法。

是的, close它是一个很好的做法,明确地发布它。

对于OP的问题非常像Java :如何通过Files.lines安全地关闭Stream 。 在Java中 ,我们可以使用try with resources来处理这个问题。 但是Scala不支持这个,也许你可以try ... finally来处理这个,比如:

 val reader = Source.fromFile("build.sbt").bufferedReader() try { reader.lines().forEach(line => { ... }) } finally { reader.close() }