permaculture playing cards*
The moose likes Java in General and the fly likes Why deleteOnExit not work? Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Spring in Action this week in the Spring forum!
JavaRanch » Java Forums » Java » Java in General
Bookmark "Why deleteOnExit not work?" Watch "Why deleteOnExit not work?" New topic
Author

Why deleteOnExit not work?

Robert Paris
Ranch Hand

Joined: Jul 28, 2002
Posts: 585
I have a class that uses a native method. The library is in my jar file. So when I load the library, it saves it to the users computer and then loads it. I then set "deleteOnExit()". However, when I exit, it leaves the DLL there. First: why? Second: is there anything I can do to remove the DLL after system exit/shutdown? Or even better, if the VM doesn't exit but my program does, is it possible to delete it then?
I'm assuming it's because it's in memory and still loaded by the VM. Is there a way to make the VM stop using it? I know that after VM shutdown, I can delete it directly, it's just deleteOnExit() doesn't do it.
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
According to the API for deleteOnExit():
Deletion will be attempted only for normal termination of the virtual machine, as defined by the Java Language Specification.

Unfortunately I couldn't find a definition for "normal termination" in the JLS or the JVM spec. However the API for System.exit(int) indicates that if the argument to exti() is anything other than 0, it's not a normal termination. I expect that exiting due to an uncaught exception is also considered abnormal. So - exactly how does your program exit?
If this doesn't explain your problem, the other thing to look at is - are you able to delete the file at all? (E.g. using delete() rather than deleteOnExit()?) Try this as an experiment; you may find the problem is more general than you thought. If you can't delete, the most common problems I know are (a) the File object may not be pointing to the same file you think it is - use getAbsolutePath() to find out. or (b) an InputStream or OutputStream associated with the file has not been closed properly beforehand (so close it).
Please post to let us know what else you learn; if there are problems with deleteOnExit() it would be useful to know about them.


"I'm not back." - Bill Harding, Twister
Robert Paris
Ranch Hand

Joined: Jul 28, 2002
Posts: 585
Thanks for the reply. Here's what I did, I created a text file in the same folder as that DLL and used the same code for both. So both files now have:
dllFile.deleteOnExit();
textFile.deleteOnExit();
The text file deletes on exit of the application, the DLL file does not. I am not exiting through an exception, nor through a call to System.exit(), the program just runs through the end of main().
What I'm going to try is this:
Subclass URLClassLoader and override findLibrary. I defer to the super class implementation first, if it's not found I check to see if it's in a jar file, if it is I save it to disk (and save the name and location), and then pass that new location on to the super class to load the library. Then in the finalize() method, I call the super class' finalize() (is that possible? It is where it unloads all the libraries) and then go through my collection of jar loaded Libraries and either delete them all from the file system or set them all as deleteOnExit().
Does this sound like a good plan? Is there anything wrong with this? A better way to do it?
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
I don't think that will work - finalizers are not normally run when the JVM exits. They're only run when GC reclaims an object and the JVM needs to keep going. If the JVM is shutting down there's no real incentive to run any GC; all memory is about to be released back into the wild anyway. Thus it's not just that there's no guarantee that finalize() will be run before the JVM exits - it is in fact extremely unlikely. I think you're going to have to look at your overall program logic and find a way to explicitly trigger the unloading of the JNI class which uses the DLL, before the JVM exits. (For that matter, be sure to try just manually using File's delete() at this point - but it probably won't work if the JNI class is still loaded.) Good luck...
Robert Paris
Ranch Hand

Joined: Jul 28, 2002
Posts: 585
duh! Thanks Jim, my brain was off on the finalizers. I did finally come up with a solution, please tell me if it sounds ok:
  • [list]1. My JarClassLoader is instantiated, it adds a shutdown hook for

  • deleting any temp jar files it will create
    * it can be instantiated so as to leave any libraries it creates on the file system if the user wants
  • 2. A class is loaded by my JarClassLoader (extends URLClassLoader)
  • 3. The class calls System.loadLibrary() same as always
  • 4. JarClassLoader's findLibrary method is called
  • 5. JarClassLoader.findLibrary() calls super.findLibrary(), if exception

  • thrown, then:
    * Will see if this resource is from a jar
    -- If it is, it creates the library on the file system (in user.dir if no "jarLibraryFolder" was set) and adds the location to its jarContainedLibraries Vector.
    * Sends the new file location to super.findLibrary()
  • 6. (Much later) The program exits and the shutdown hook is called

  • 7. The shutdown hook was a Runnable created
    on the fly in JarClassLoader something like this:

    The DeleteLibraries is basically a while loop that keeps trying to delete the file created until it's either successful or the timeout is reached.
    This was the only thing that worked. When i tried setting the library file to delete on exit, it never worked, I think because it's held as being used until the current process ends (so other threads, and shutdown hooks won't do it). This is because, when you look at the Java API implementation code (from Sun), the ONLY place that the libraries are freed from memory is in the finalize() method, which as you pointed out, won't be called unless the GC comes along.
    The point of this, is simply a deployment issue. it allows the use of native libraries with your applciation, while allowing them to be delivered in a jar (much cleaner delivery of application), automatically deployed and deployed only temporarily (for execution) if so desired (to keep the file system clean after use is finished).
     
    I agree. Here's the link: http://aspose.com/file-tools
     
    subject: Why deleteOnExit not work?