文件deleteOnExit()函数即使在删除文件后也会保持引用指针处于打开状态

时间:2014-11-18 09:21:09

标签: java linux file io

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

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

      

    (如果我在上述假设上错了,请纠正我)

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

    1. 如果我删除deleteOnExit(),我将不得不手动删除所有对象。这样做,我的指针仍然保持打开状态(在Linux上使用lsof +al1查看打开的文件)为什么会发生这种情况?
    2. 如果我删除delete(),那么我将不得不等到VM停止以删除tempFiles(这在Production Server中是非常罕见的情况)。 (巨大空间利用
    3. 如果我手动删除文件,是否可以从deleteOnExit()列表中删除文件?

3 个答案:

答案 0 :(得分:1)

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

然而,我们至少受到警告(有点)。 Javadoc for deleteOnExit说:

  

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

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

然而,在我看来,你的问题意味着它自己的解决方案。你说:

  

如果我删除delete(),那么我将不得不等到VM停止以删除tempFiles(这在Production Server中非常罕见)。

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

答案 1 :(得分:0)

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

fileVar = null;

之后

fileVar.delete();

答案 2 :(得分:0)

我也看到了这个问题。我暂时"修复"在调用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。