If you take a look at the javadoc for File.deleteOnExit()
it clearly states:
Once deletion has been requested, it is not possible to cancel the request. This method should therefore be used with care.
It is relatively easy to overlook this kind of statement. In my case it led to a slow memory leak that was reported in glu. In the end, finding out the memory leak turned out to be relatively simple thanks to jmap
and YourKit (although it seems to always be simple after the fact :)).
The piece of (groovy) code that was causing the issue was the following:
What the code does: it creates a temporary file, then downloads the location
(URL) in this temporary file and simply returns the content as a String
. In order to be safe, I called tempFile.deleteOnExit()
, but as you can see the file is deleted in the finally
.
Non intuitively (but to be fair as stated in the javadoc!), once deletion has been requested, there is no way to cancel it, even if you delete the file!
The implementation of java.io.File.deleteOnExit()
simply keeps a list of String
representing all the files that need to be deleted when the VM exits. And this list grows and grows as the cat
method is called (which in this specific scenario was every 15 seconds, so the leak took many weeks to manifest itself!).
Looking back at the issue and this specific java call, I actually do not see a real use for it and I have decided to ban it from my code for several reasons as I actually think it is evil:
- it gives you a false sense of security: “oh the VM will take care of it…” which is not true: if the VM does not terminate properly, for any particular reason (power outage,
kill -9
,…) then the files will simply not be deleted. If your code relies on the fact that those files should not be present on VM restart then one day you will have a nasty surprise. - calling this method will eventually lead to a memory leak (granted of course it is called repeatedly, even if the frequency is very slow!)
In the end, dealing with files is hard. If you generate a lot of temporary files you need to delete them at some point or another or you will fill up the disk. It is not always easy to know when a temporary file is safe to be deleted, especially if a method creates it and returns it. I think this is where java.io.File.deleteOnExit()
totally fails: it gives you the impression that it implements GC for files but as I mentionned before there are a lot of shortcommings.