【问题标题】:File deleteOnExit() function keeps Reference Pointer open even after the file is deleted文件 deleteOnExit() 函数即使在文件被删除后仍保持引用指针打开
【发布时间】:2015-01-15 10:09:20
【问题描述】:
  1. 我正在使用 java.io.File.createTempFile() 在我的应用程序中创建临时文件。
  2. 在创建文件时,我为该文件对象调用了deleteOnExit()

此代码在我的应用程序中的许多场景中使用。有时,临时文件的大小太大,所以我必须在我的工作完成后立即删除它。所以我为某些对象调用File.delete()

现在的问题是,当我使用delete() 函数删除文件时,这个已删除文件的引用指针是打开的(因为它是临时文件(我的观点))。因此,我面临内存泄漏问题。

(如果我对上述假设有误,请纠正我)

我在我的环境中面临高磁盘利用率,我发现“df”和“du”命令的输出中存在超过 30GB 的差异(“df”查看 FS 本身的统计信息,而“ du' 忽略已删除的文件描述符)。

  1. 如果我删除 deleteOnExit(),我将不得不手动删除所有对象。这样做,我的指针仍然保持打开状态(在 linux 上使用 lsof +al1 查看打开的文件)为什么会发生这种情况?
  2. 如果我删除 delete(),那么我将不得不等到 VM 停止才能删除 tempFiles(这在生产服务器中非常罕见)。 (巨大的空间利用率

如果我手动删除文件,是否有关于如何从 deleteOnExit() 列表中删除文件的解决方案?

【问题讨论】:

  • 我在this answer 中详细说明了File.deleteOnExit() 和使用StandardOpenOption.DELETE_ON_CLOSE 在进程终止时的行为不同。这表明它们的实现方式不同,所以也许后者也可以解决您的问题。
  • 您的选项的问题是: 当打开由其他实体同时打开的文件时,不建议使用此选项。关于何时以及如何删除文件的许多细节是特定于实现的,因此未指定。

标签: java linux file io


【解决方案1】:

我怀疑您的分析是正确的,这可能被视为 Java 中的一个错误:一旦您调用 delete,可以期望删除 deleteOnExit 创建的引用。

但是,我们至少被警告(有点)。 Javadoc for deleteOnExit 说:

一旦请求删除,就无法取消请求。因此,应谨慎使用此方法。

所以我想在deleteOnExit 之后调用delete 会被认为是粗心。

但是,在我看来,您的问题暗示了它自己的解决方案。你说:

如果我删除 delete(),那么我将不得不等到 VM 停止删除 tempFiles(这在生产服务器中非常罕见)。

如果 JVM 很少结束,那么 deleteOnExit 很少会对您有任何好处。这表明解决方案是处理您自己的删除,方法是让您的应用程序在完成文件后调用delete,并注意使用deleteOnExit

【讨论】:

  • 如果我使用delete() 而根本不使用deleteOnExit(),指针仍然保持打开状态。这是因为jsvc
  • 嗯,没接触过jsvc。我可以看到它如何导致各种复杂性。您可能想更改您的问题以反映这一事实。还要解释一下你是怎么知道jsvc是原因的。
【解决方案2】:

指针将保持打开状态,直到应用程序释放该文件的资源。试试

fileVar = null;

在你之后

fileVar.delete();

【讨论】:

    【解决方案3】:

    我也看到了这个问题。在调用 delete 之前,我已通过执行以下操作暂时“修复”它:

    FileChannel outChan = new FileOutputStream(tmpfile, true).getChannel();
    outChan.truncate(newSize);
    outChan.close();
    

    这至少可以使 tmp 文件不占用磁盘空间,并且 df 和 du 报告相同的统计信息。它仍然会泄漏文件描述符,我认为它会泄漏少量堆。

    值得注意的是 File.delete() 返回一个布尔值来指示删除是否成功。它可能会默默地为您失败,并且您实际上有一个未关闭的文件流,这会阻止删除。您可能想尝试使用以下调用,如果无法删除文件,它将抛出带有诊断的 IOException。

    java.nio.file.Files.delete(tmpfile.toPath)
    

    如果这仍然不能为您解决问题,我有幸使用file-leak-detector,它跟踪通过流访问文件的时间,并在创建流时获取堆栈跟踪。如果流没有关闭,堆栈跟踪可以将您指向该流的来源。不幸的是,它并未涵盖所有形式的文件访问,例如 nio。

    【讨论】:

      猜你喜欢
      • 2020-03-27
      • 1970-01-01
      • 1970-01-01
      • 2017-05-03
      • 2023-03-12
      • 1970-01-01
      • 2017-03-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多