java - 无法删除文件,因为 JVM 持有它 - 一个棘手的问题

标签 java file stream garbage-collection jvm

我的帖子有点太长了,抱歉。这是一个总结:

  • 无法删除磁盘上的文件(“JVM 持有文件”错误)。无论是从 Java 代码中删除还是尝试从 Windows 中手动删除文件。
  • 该文件的所有流都关闭并设置为空。所有文件对象都设置为空。
  • 此时程序什么都不做;但等待 30 分钟后,我可以从 Windows 中删除该文件。诡异的。该文件不再被java使用了吗?另外,由于程序中没有发生任何事情,这表明它不可能是我忘记的某个流(另外,我三次检查没有打开任何东西)。
  • 调用 System.gc() 似乎在文件较小时有效。当他们达到大约 20MB 时没有帮助。

[EDIT2] - 我尝试编写一些基本代码来解释,但这很棘手。对不起,我知道这样回答很难。当然,我可以写下如何打开和关闭流:

BufferedWriter bw = new BufferedWriter(new FileWriter(new File("C:\\folder\\myFile.txt")));
for(int i = 0; i < 10; i++)
{
    bw.write("line " + i);
    bw.newLine();
}
bw.close();
bw = null;

如果我使用了文件对象:

File f = new File("C:\\folder\\myFile.txt");
// use it...
f = null;

基本代码,我知道。但这基本上就是我所做的。 我知道 一个事实 我已经以这种方式关闭了所有流。 我知道一个事实,在我无法删除文件的 30 分钟间隔内程序中没有任何反应,直到我以某种方式神奇地可以。

即使没有连贯的代码,也感谢您的输入。 我很感激。


很抱歉在这里没有提供任何具体的代码,因为我无法查明问题所在(不完全与具体代码相关)。无论如何,事情是这样的:

我编写了一个程序,可以读取、写入和修改磁盘上的文件。由于多种原因,读/写的处理是在不同的线程中完成的,该线程不断运行。

在某些时候,我终止了“读/写”线程,只保留主线程——它等待来自套接字的输入,与文件完全无关,什么都不做。然后,我尝试删除文件(使用 File.delete(),甚至尝试了 nio.Files 删除选项)。

问题是 - 这很奇怪 - 有时有效,有时无效。即使手动转到文件夹并尝试通过 Windows 删除文件,也会给我“文件由 JVM 打开”消息。

现在,我很清楚保留各种流对文件的引用会阻止我删除它。现在已经过去了:) 我已确保所有流都已关闭。我什至将它们的值设置为 null,包括我使用过的任何"file"对象(尽管它应该没有任何区别)。全部设置为null,全部关闭。生成所有这些线程的线程——“读/写”线程——好吧,它终止了,因为它的 run() 方法结束了。

通常,如果我等待大约 30 分钟,JVM 仍在运行,我可以从 Windows 手动删除该文件。错误神奇地消失了。当 JVM 关闭时,我总是可以立即删除文件。

我迷路了。在尝试删除文件之前尝试专门调用 System.gc() ,甚至调用它 10 次(这并不重要)。有时它会有所帮助,但在其他情况下,例如,当文件变大(比如 20MB)时,这并没有帮助。

我在这里错过了什么? 显然,这不可能是我隐含的错误(没有关闭一些流),因为读/写线程已经死了,主线程等待一些不相关的东西(所以程序处于“停顿”状态),我已经明确关闭了所有流,甚至使引用无效 (inStream = null),调用垃圾收集器。

我错过了什么?为什么文件在 30 分钟后“可删除”(当时什么也没有发生——我的代码中没有)。我是否缺少一些温和的引用/垃圾收集之类的东西?

最佳答案

您正在做的事情只会带来问题。你说“如果发生 IOexception,它会立即打印出来”,这可能是真的,但鉴于发生了一些无法解释的事情,我们最好怀疑它。

我会首先确保一切都始终关闭,然后我会关心相关的逻辑(日志记录、退出...)。

反正你做的不是资源应该怎么管理。 answer abovenot exactly correct either .无论如何,try-with-resources(@lombok.Cleanup 除外)是唯一的方法,清楚地表明没有任何东西是开放的。其他任何事情都更复杂,更容易出错。我强烈建议在任何地方都使用它。这可能需要做一些工作,但它也会迫使您重新检查所有关键代码段。

诸如使引用无效和调用 GC 之类的事情应该没有帮助......如果他们看起来有帮助,那可能是一个机会。

一些想法:

  • 您是否使用内存映射文件?
  • 您确定 System.exit 没有被安全管理员禁用吗?
  • 您是否正在运行防病毒软件?他们喜欢在文件写完后立即扫描文件。

顺便说一句,锁定文件是我从未开始玩 WOW 的原因之一。有时,在罪魁祸首消失后,锁定仍然存在很长时间,至少根据我可以使用的工具。

关于java - 无法删除文件,因为 JVM 持有它 - 一个棘手的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37246541/

相关文章:

c - 从 C 中的文本文件读取数据时出现段错误

c# - 为什么我的 hello world with streams 不显示任何内容?

Python:通过查看扩展名来确定文件类型

java - 用于跟踪登录 session 的 Android 应用策略

java - 按下按钮并发送消息(Spring Boot 和 Vaadin)

java - 我可以从 spring bean 访问 graphql-context 吗?

ios - 在 iPhone 上继续中断的下载

java - Netty 分块输入流

PHP: get_headers 设置临时 stream_context

java - 在 Spring 中向对象添加日历值