3
  1. I am creating temporary files in my application using java.io.File.createTempFile().
  2. While creating file, I have called deleteOnExit() for that File object.

This code is used in many scenarios in my application. Sometimes, the size of temp files is too large and so I have to delete it immediately after my job is completed. So I am calling File.delete() for some objects.

Now the problem is, when I delete the file using delete() function, the reference pointer is open for this deleted file(because of it being temp file(My opinion)). Because of this, I am facing memory leakage issue.

(Correct me if I am wrong on my above hypothesis)

I am facing high disk utilization on my environment, I found a discrepancy of over 30GB in the output of the 'df' and 'du' command ('df' looks at the stat of the FS itself whereas 'du' ignores deleted file descriptors).

  1. If I remove deleteOnExit(), I will have to take care of deleting all the objects manually. Doing this, my pointers are still remaining open(Used lsof +al1 on linux to see open files) Why is this happening?
  2. If I remove delete(), then I will have to wait until VM stops to get tempFiles deleted(which is a very rare case in Production Server). (Huge Space Utilization)

Is there any Solution on how I can remove file from deleteOnExit() list if I am manually deleting the file?

SID
  • 606
  • 2
  • 7
  • 17
  • I elaborated in [this answer](http://stackoverflow.com/a/26759701/2711488) that `File.deleteOnExit()` and using `StandardOpenOption.DELETE_ON_CLOSE` behave differently when a process is terminated. This suggests that they are implemented differently, so maybe the latter could also solve your problem. – Holger Nov 18 '14 at 09:31
  • The problem with your option is: _This option is not recommended for use when opening files that are open concurrently by other entities. Many of the details as to when and how the file is deleted are implementation specific and therefore not specified._ – SID Nov 18 '14 at 10:15

3 Answers3

3

I suspect that your analysis is correct, and that could be seen as a bug in Java: once you call delete, it would be fair to expect the reference created by deleteOnExit to be be removed.

However, we are at least warned (sort of). The Javadoc for deleteOnExit says:

Once deletion has been requested, it is not possible to cancel the request. This method should therefore be used with care.

So I guess calling delete after deleteOnExit would be considered careless.

However, it seems to me that your question implies its own solution. You say:

If I remove delete(), then I will have to wait until VM stops to get tempFiles deleted(which is a very rare case in Production Server).

If the JVM is very rarely ended, then deleteOnExit will very rarely do you any good. Which suggests that the solution is to handle your own deletions, by having your application call delete when it is finished with a file, and note use deleteOnExit at all.

Martin McCallion
  • 743
  • 1
  • 4
  • 22
  • If I use `delete()` it and do not use `deleteOnExit()` at all, still the pointer is remaining open. This is because of jsvc – SID Nov 18 '14 at 14:09
  • Hmm, haven't come across jsvc before. I can see how it might cause all sorts of complexity. You might want to change your question to reflect that fact. Also explain how you know that jsvc is the cause. – Martin McCallion Nov 18 '14 at 14:45
1

The pointer will remain open until the application releases the resource for that file. Try

fileVar = null;

after your

fileVar.delete();
anitag95
  • 307
  • 2
  • 16
1

I see this problem as well. I've temporarily "fixed" it by executing the following, prior to calling delete:

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

This at least makes it so that the tmp files don't consume disk space, and df and du report the same stats. It does still leak file descriptors, and I presume it leaks a small amount of heap.

It's noteworthy that File.delete() returns a boolean to indicate if the delete succeeded. It's possible that it's silently failing for you, and you actually have an unclosed stream to the file, which prevents the delete. You may want to try using the following call, which will throw an IOException with diagnostics if it is unable to delete the file.

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

If that still doesn't isolate the problem for you, I've had some luck using file-leak-detector, which keeps track of the time files are accessed via streams and grabs a stack trace at the time the stream is created. If a stream doesn't get closed, the stack trace can point you to the origin of that stream. Unfortunately, it doesn't cover all forms of file access, such as nio.

jsears
  • 4,511
  • 2
  • 31
  • 36