JVM会自动关闭文件吗?

问题描述 投票:0回答:2

我在某处读到,不必自己关闭它,只需保留它,JVM 会帮助你做到这一点。这是真的吗?

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

Source.fromFile(fileName).getLines() 

直接,无需

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

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

如果有人可以在这里留下一些链接或解释,那就太好了。

java scala file jvm
2个回答
7
投票

我在某处读到,不必自己关闭它,只需保留它,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 仅在堆(或堆的一部分)达到给定的“满度”阈值时运行。如果应用程序没有分配很多对象,则可能需要很长时间才能达到阈值。

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


0
投票

是的,在某些方面确实如此,JVM将在GC时通过调用

finalize
方法帮助释放文件描述符(您可以尝试通过
System.gc()
来验证它)。

并且完全同意我们需要在不需要时显式关闭

InputStream
并释放文件描述符

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

finalize
方法。

是的,明确释放它是一个很好的做法。


对于OP来说,问题非常像

Java

的问题:如何通过close安全地关闭

Stream
。在
Java
中,我们可以使用try with resources来处理这个问题。但是Scala不支持这个,也许你可以尝试用Files.lines来处理这个,比如:

try ... finally

© www.soinside.com 2019 - 2024. All rights reserved.