java.io.File.createTempFile()
在我的应用程序中创建临时文件。deleteOnExit()
。 此代码在我的应用程序中的许多场景中使用。有时,临时文件的大小太大,所以我必须在我的工作完成后立即删除它。所以我正在为File.delete()
调用某些对象。
现在的问题是,当我使用delete()
函数删除文件时,该删除文件的引用指针是打开的(因为它是临时文件(我的意见))。因此,我面临内存泄漏问题。
(如果我在上述假设上错了,请纠正我)
我在我的环境中面临高磁盘利用率,我发现'df'和'du'命令的输出差异超过30GB('df'查看FS本身的统计数据,而' du'忽略已删除的文件描述符)。
lsof +al1
查看打开的文件)为什么会发生这种情况?如果我手动删除文件,是否可以从deleteOnExit()列表中删除文件?
答案 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。