Win a copy of Design for the Mind this week in the Design forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

URLClassLoader won't free JAR files

 
Francesc Martinez
Greenhorn
Posts: 24
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello,

I've developed a simple JarFileLoader using URLClassLoader.
Now I would like it to reload new JAR files and free the old ones, but it seems URLClassLoader locks the JAR files and won't release them until the JVM is closed.

I've read that, In Java 7, they're going to add the Closeable.close() method to URLClassLoader but, in the meantime, as to Java 5, is there any way to release the loaded JAR files? Or do you know any other class/API that lets you do it (from Apache perhaps? They need to do it in Tomcat!).

Thank you very much!!!
 
Ernest Friedman-Hill
author and iconoclast
Marshal
Pie
Posts: 24208
35
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Since the very beginning of Java, there has been one way, and one way only, to unload a class: by discarding the ClassLoader that loaded it. Normally, this works just fine. For example, when a servlet container reloads a web app, it discards the classloader that originally loaded that app, creates a new one, and loads it anew. So that's basically what you need to do.
 
Ulf Dittmer
Rancher
Posts: 42967
73
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
This may be more work than you want to embark upon (although it pays back in the long run), but this sounds like a perfect application for an OSGi container like Apache Felix.
 
Francesc Martinez
Greenhorn
Posts: 24
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ernest Friedman-Hill wrote:Since the very beginning of Java, there has been one way, and one way only, to unload a class: by discarding the ClassLoader that loaded it. Normally, this works just fine. For example, when a servlet container reloads a web app, it discards the classloader that originally loaded that app, creates a new one, and loads it anew. So that's basically what you need to do.


But, how can I discard the classloader? Setting it to null doesn't work: jar files are still locked.
 
Francesc Martinez
Greenhorn
Posts: 24
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ulf Dittmer wrote:This may be more work than you want to embark upon (although it pays back in the long run), but this sounds like a perfect application for an OSGi container like Apache Felix.


I don't know much about OSGi; I've read it's about services.

Do you mean I could start a service (with some jars) so later I could restart that service (when I need to update the jars)?
 
Ulf Dittmer
Rancher
Posts: 42967
73
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I don't know much about OSGi; I've read it's about services.

Services are part of it, but it's a very broad-based framework that can be used for may purposes. You can find some introductory articles linked in http://faq.javaranch.com/java/OSGiLinks

Do you mean I could start a service (with some jars) so later I could restart that service (when I need to update the jars)?

Yes, that's a common use case for OSGi. There are several ways in which this could work: either the app user could click a button/menu that causes the service to be discarded and reloaded, or the app could be set up to monitor a directory that contains the jar files and trigger the reloading automatically whenever there's a change, or the service code could monitor itself and notify the host app that it should trigger a reload if a file changes.
 
Ulf Dittmer
Rancher
Posts: 42967
73
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
But, how can I discard the classloader? Setting it to null doesn't work: jar files are still locked.

This may go without saying, but you also need to make sure that all classes that have been loaded through that classloader are also eligible for garbage collection (meaning that none of their objects are still referenced from anywhere in your code, like in a collection).
 
Francesc Martinez
Greenhorn
Posts: 24
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ulf Dittmer wrote:
But, how can I discard the classloader? Setting it to null doesn't work: jar files are still locked.

This may go without saying, but you also need to make sure that all classes that have been loaded through that classloader are also eligible for garbage collection (meaning that none of their objects are still referenced from anywhere in your code, like in a collection).


That's not the problem, I think. I've written a small program where I create a URLClassLoader, I add a jar to it and then load a class from that jar (I just call loader.loadClass(), ignoring the returned class and not instantiating it). Then, after nulling the URLClassLoader... the jar file is still locked.

This is pseudocode of what I did:



Now, before exiting the program, I try to delete "some.jar", but it's locked!
 
Ulf Dittmer
Rancher
Posts: 42967
73
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It seems that that should work. Of course, it only would work if the classloader really did get garbage-collected. Try calling System.gc() 5 times in a row, then putting the thread to sleep for a few seconds, and then try to delete the file. That might give the JVM some extra time and inclination to perform a GC.
 
Francesc Martinez
Greenhorn
Posts: 24
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ulf Dittmer wrote:It seems that that should work. Of course, it only would work if the classloader really did get garbage-collected. Try calling System.gc() 5 times in a row, then putting the thread to sleep for a few seconds, and then try to delete the file. That might give the JVM some extra time and inclination to perform a GC.


Hehe, that seems like a witch recipe!
I'd like to find something more "scientific".

Anyway, I'll try it. Thanks!
 
Ernest Friedman-Hill
author and iconoclast
Marshal
Pie
Posts: 24208
35
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Frank,

Since JarClassLoader is your own class, we can't vouch for how it behaves. Does it open or close jar files for reading by itself? Or does this happen only in the parent URLClassLoader? Maybe we could see the JarClassLoader code.
 
Francesc Martinez
Greenhorn
Posts: 24
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ernest Friedman-Hill wrote:Frank,

Since JarClassLoader is your own class, we can't vouch for how it behaves. Does it open or close jar files for reading by itself? Or does this happen only in the parent URLClassLoader? Maybe we could see the JarClassLoader code.


Here is the code:

 
Maneesh Godbole
Saloon Keeper
Posts: 11021
12
Android Eclipse IDE Google Web Toolkit Java Mac Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Frank Martin Carl wrote:


Please check your private messages for an important administrative matter
 
Paul Clapham
Sheriff
Pie
Posts: 20958
31
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Frank Martin Carl wrote:I've developed a simple JarFileLoader using URLClassLoader.
Now I would like it to reload new JAR files and free the old ones, but it seems URLClassLoader locks the JAR files and won't release them until the JVM is closed.


In the application I use which does that, this is the process they use: they watch for changes in the JAR file. When they see one, they copy the JAR file to a temporary directory and use that, I assume via a URLClassLoader. That way they don't care whether the temporary copy remains locked after they stop using it.
 
Francesc Martinez
Greenhorn
Posts: 24
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Paul Clapham wrote:
Frank Martin Carl wrote:I've developed a simple JarFileLoader using URLClassLoader.
Now I would like it to reload new JAR files and free the old ones, but it seems URLClassLoader locks the JAR files and won't release them until the JVM is closed.


In the application I use which does that, this is the process they use: they watch for changes in the JAR file. When they see one, they copy the JAR file to a temporary directory and use that, I assume via a URLClassLoader. That way they don't care whether the temporary copy remains locked after they stop using it.


Great idea Paul, thanks!

The only problem is those temporary copies will be locked. But it's the best solution I've seen so far.
 
Jaikiran Pai
Marshal
Pie
Posts: 10447
227
IntelliJ IDE Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Which operating system are you testing this on? Windows OS has some known issues with this kind of file locking. If you have access to some *nix system, try the same code over there.
 
Jaikiran Pai
Marshal
Pie
Posts: 10447
227
IntelliJ IDE Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Jaikiran Pai wrote:Windows OS has some known issues with this kind of file locking.


See this and the JDK bug referenced in that blog.
 
Francesc Martinez
Greenhorn
Posts: 24
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Jaikiran Pai wrote:
Jaikiran Pai wrote:Windows OS has some known issues with this kind of file locking.


See this and the JDK bug referenced in that blog.


Great article, thank you very much!

By the way, I'm using Windows (although the article says it will happen also with UNIX).
 
It is sorta covered in the JavaRanch Style Guide.
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic