JVM是否自动关闭文件?

时间:2017-12-12 10:09:24

标签: java scala file jvm

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

假设我需要使用

从文件中获取数据
Source.fromFile(fileName).getLines() 

直接,没有

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

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

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

2 个答案:

答案 0 :(得分:5)

  

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

部分正确。

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

然而,依靠GC来做这件事一个坏主意

  • 如果文件句柄可以访问,那么GC不会最终确定它。
  • 您可以知道GC何时运行 1
  • 当GC运行时,它不一定会收集所有垃圾 2
  • 排队等待最终确定的对象实际上不会在GC完成之前完成。 (参见@ Holger的评论)

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

以下是您可以运行(在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.<init>(FileInputStream.java:138)
    at java.io.FileInputStream.<init>(FileInputStream.java:93)
    at Test.main(Test.java:6)

1 - 典型的GC仅在堆(或堆的一部分)达到给定阈值&#34; fullness&#34;时运行。如果应用程序没有分配许多对象,则可能需要很长时间才能达到阈值。

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

答案 1 :(得分:0)

是的,在某些方面它是真的, JVM 将有助于在GC调用finalize方法时释放文件描述符(您可以尝试通过System.gc())。

并且完全同意,当我们不需要时,我们需要明确关闭InputStream并释放文件描述符

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

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

并且OP的问题非常类似于 Java :如何通过Stream安全地关闭Files.lines。在 Java 中,我们可以使用 try with resources 来处理此问题。但 Scala 不支持此功能,也许您可​​以尝试使用try ... finally来处理此问题,例如:

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