I am looking for a way to reload a class into Java at runtime. The motivation is to make debugging more efficient. The application is a typical client/server design that synchronously processes requests. A "handler" object is instantiated for each request. This is the only class I intend to dynamically replace. Since each request deals with a fresh instance, reloading this class won't have any side-effects. In short, I do not want to restart the entire application every time there is a change to this module.
In my design, the Java process becomes aware that a .class file has been updated in the classpath in between requests. When this happens, the "handler" class is unloaded and a new one is loaded.
I know I can use the classLoader interface to load in a new class. I seem to be having trouble finding the proper way of "unloading".
Classes will be unloaded and garbage collected like any other object, if there is no remaining reference to them. That means there must be no reachable instance of the class (as loaded by that particular classloader instance) and the classloader instance itself must be eligible for garbage collection as well.
So basically, all you have to do is to create a new classloader instance to load the new version of the class, and make sure that no references to instances of the old version remain.
I believe that you actually need to have a hierarchy of classloaders, and in order to reload you actually get rid of the low level classloader (by normall GC means), and hence all the classes it loaded. So far as I know this technique is used by Java EE app servers for reloading applications, and there's all manner of fun results when framework code loaded in one classloader wants to use classes loaded somewhere else.
As of 2015 also java's class reloading is a missing feature.
Use OSGi to create a class reloading application.
Use jrebel for testing. There are a few others which does the same thing.
Use application server and externalize the parts which you want to reload into a separate web application. Then keep deploying/undeploying. You will eventually get some perm gen space overflow kind of errors due to dangling old ClassLoader instances.
Use a script runner to execute parts of changeable code. JSR-223 Java Scripting API support for the scripting language "Java".
I had written a series about class reloading. But all of those methods are not good for production.
The blog and source codes in google sources
IMHO this class reloading is messy in java and its not worth trying it. But I would very much like this to be a specification in java.
Related
This is a high-voted example of memory leak from StackOverflow:
Not unloading Singletons when bringing down a Java EE application. Apparently, the Classloader that loaded the singleton class will retain a reference to the class, and hence the singleton instance will never be collected. When a new instance of the application is deployed, a new class loader is usually created, and the former class loader will continue to exist due to the singleton.
1) I do not understand how can I "unload" a singleton and what is meant by "bringing down a Java EE application". Could you provide code examples (wrong and right code samples) and scenarios?
2) From the same stackoverflow post:
Take any web application running in any servlet container (Tomcat, Jetty, Glassfish, whatever...). Redeploy the app 10 or 20 times in a row (it may be enough to simply touch the WAR in the server's autodeploy directory.
Unless anybody has actually tested this, chances are high that you'll
get an OutOfMemoryError after a couple of redeployments, because the
application did not take care to clean up after itself. You may even
find a bug in your server with this test.
The problem is, the lifetime of the container is longer than the
lifetime of your application. You have to make sure that all
references the container might have to objects or classes of your
application can be garbage collected.
If there is just one reference surviving the undeployment of your web app, the corresponding classloader and by consequence all
classes of your web app cannot be garbage collected.
Threads started by your application, ThreadLocal variables, logging
appenders are some of the usual suspects to cause classloader leaks.
I cannot understand how is it possible that container (Tomcat classes/objects) holds references to objects or classes of my application and it is my fault. Automatic memory management means I don't have to care about freeing memory, right? So what shall I take care of if my application runs within Tomcat or another container?
A single jvm can be used as "application server". It hosts containers, coming in as "packages" (EAR or WAR files for example) that can be dynamically added / removed from the jvm.
You achieve that by using the capabilities of the class loader. But a class loader keeps track of all the classes it loaded. So, to free up the old class loader it has to forget all classes it knows about. But it can't for singletons done wrong.
Or quoting from IBM:
An object retains a reference to the class it is an instance of. A class retains a reference to the class loader that loaded it. The class loader retains a reference to every class it loaded. Retaining a reference to a single object from a web application pins every class loaded by the web application. These references often remain after a web application reload. With each reload, more classes are pinned which leads to an out of memory error
By request from the OP, I tried to find examples for "bad" respectively "working" singleton implementations, but I couldn't find any.
But to give a different perspective: since we have enums, we can use enums to implement a singleton (see here). So, probably the reasonable answer today is: simply use enums. And given the fact that there isn't much to find on the internet regarding this subject, my (personal) gut feeling is: this is simply not a relevant problem in the real world (any more).
I am looking for a way to replace a jar with old functionality with a new one without stopping the whole application. I have googled for this a little bit (Unloading classes in java?, Dynamically loadable and unloadable application modules in Java - how?), and have found 3 possible solutions:
OSGI, which looks too complicated for my purposes: class unloading is the only thing I need from this powerful specification.
Own implementation, which implies creating own Classloader, loading jars with its help, and when time comes to dismiss the jar - expose Classloader instance to GC and hope that GC will remove it together with all loaded jars, which may not happen immediately.
Copy the stuff application servers do :) That is the purpose of my question.
Is there any explanation on how Tomcat unloads the classes (wars)? Is it possible to reuse this in my application?
PS
Just while I was writing this post 2 strange ideas came into my head:
may be we can start another instance of application with new set of jars and switch input and output data flows from old one to new one. If there is a place to preserve state - it can be more quick than full restart.
may be Spring may help? It can dynamically register beans, but this looks like somewhat ugly solution, and it cannot unload them anyway; may be, Spring Boot may help?
A class can be unloaded only when it and its class loader are unreachable and thus eligible for garbage collection. Since the class loader can reach every class it loaded and every class loaded by a class loader can reach its class loader and every object which is an instance of a class can reach its class, this means that the class loader, all the classes it loaded and all the objects which are an instance of those classes must all be unreachable and eligible to be garbage collected. Only then, can a class be "unloaded" when that complete object graph is garbage collected.
I can only partially answer you questions, however better than nothing... You are right, modularity is a quite a tedious topic (at least until there's Java 9).
Ad idea 2 (Spring): I already spent some thoughts on Spring Boot over here and came to the conclusion that I'll stick either to OSGI (it's worth getting into it) or to a pure Microservice architecture.
I suppose that you are not doing whole redeployment of application, but don't want to restart whole application every time while you are developing it
If you want to change functionality of methods without changing class or method signatures you can use Spring Loaded
Add dependency to your project https://mvnrepository.com/artifact/org.springframework/springloaded/1.2.6.RELEASE
Set JVM option -javaagent:path\springloaded-version.jar -noverify
This option can be set in several ways depending on how you run tomcat
I have Broadleaf eccomerce web site and I added this option to MAVEN_OPTS in batch script that runs embedded tomcat or you can configure that in Run configuration for Tomcat VM options
read http://docs.spring.io/spring-boot/docs/current/reference/html/howto-hotswapping.html
How does class-reloading works in Tomcat when it comes to reloading JSPs (I am talking about the internal architecture)?
I know that each JSP is compiled to a Java class. But how does the classloader (which is unique per web application) reload these generated classes given that a classloader does not allow class unloading and without collecting too much garbage?
A JasperLoader instance is the classloader loads jsp generated servlets.
The jsp compiler "throw away" (set to null) the old JasperLoader instance when it generates a newer servlet class file.
Quote from the comments in JspServletWrapper.setServletLastModifiedTime:
Really need to unload the old class but can't do that. Do
the next best thing which is throw away the JspLoader so
a new loader will be created which will load the new
class.
See also where this method is called after compiling.
The standard Java class loader never unloads a class. Tomcat has its own class loaders, which can replace an old instance of a class with a new instance, and then orphans the old instance, making it available to the garbage collector in the usual manner.
Somewhere along the line I read that if a class is not used for some specified period of time, Tomcat will unload it. But I can't find any reference for that at the moment.
Read the code if you want an education.
Start here: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/jasper/servlet/JspServlet.java?view=markup
I have a piece of software, contained in a single .jar that is doing its job but sometimes I need to quickly push a bug fix necessitating replacing the .jar file in a central location, unfortunately if there is a currently running execution of this jar file if I replace it then it crashes with "class not found" error. I thought that once a jar file is executed the JVM will cache it in memory and won't do any reads from the disk but apparently this is not the case, how can (if possible at all) this be remedied?
EDIT:
The application is not web-based. It's normal Java SE.
JAR files are not loaded into memory in bulk, as other shared object libraries are. Their classes are loaded into memory on a demand basis, so if you remove a JAR file and a class lookup needs to occur, the file handle the class loader will be invalid (because the open file it referenced is now gone) and you will get an error.
Operating systems manage the file handles, so replacing an open file with a new copy is not going to fool anyone. You need to close the file first, which often can only be done by garbage collecting the class loader. If you are using the system class loader, then that means shutting down the JVM.
People have written frameworks to create custom class loaders that can be disposed independently of the system class loader; however, this does complicate class loading. While it can accomplish what you are asking, it cannot do so without restructuring your existing program to accommodate the lookup of classes in the framework's class loaders (and accommodating the loss and gain of class loaders over time).
If you want to try such a framework, see Christian's post. If you want to learn a bit more about how one project uses class loaders to facilitate its needs, take a peek under the covers of Apache's Tomcat, which restricts web applications within their own class loaders.
Often you might find that the correct answer really is to stop the service prior to deployment, and start it after deployment.
The only two possibilities I can think of are using JRebel or OSGi.
For a project, we need a way to run user scripts that can come with attached JAR files with additional classes.
What are my options when I want to write a couple of tests to make sure normal script don't leave anything dangling behind?
I specifically need to know: Are all classes from the attached JARs "unloaded"?
Note: I'm not looking for the 100% super-watertight solution that works across all versions of Java from 1.0 to 7. Right now, I just need to be better than "I have no idea".
The likely best option is to ensure your loaded jars are loaded by a specific class loader, and then to discard that class loader (after discarding all the objects).
As far as unit testing the unloading, if you go with this option, you need to extend your testing framework and customized class loaders to have a "create class loader on demand" flag. Then you load the class once with the flag on, discard the class loader, and attempt to load the class again with the flag off. If the class is truly not reachable, the second attempt should throw a class not found exception. You then wrap your unit tests to pass if they fall into the exception, and fail if they succeed in hitting the line after the second load attempt.
If you are disposed to use more than pure-Java tools, an OSGi container might be a consideration. Most of the established OSGi container implementations explicitly test class unloading.
I wouldn't try to unit test this. Instead, I'd run the JVM with -XX:-TraceClassUnloading and look to see if the classes in question show up in the trace output.
It looks like what you want to test is that hose scripts don't have a classloader leak.
To do that, I'd create a WeakReference to the ClassLoader used to load that JAR, then run the script, then call System.gc() and afterwards assertNull(reference.get())
This depends entirely on the way you allow the scripts to run. Do they have access to the classes of the rest of the application?
The typical way to leak memory in Java is to have a static reference. A static reference is only static within the ClassLoader of the class that contains it. So, if you load your user scripts using a ClassLoader you manage yourself (and you should do this anyway), then the references (static or not) inside will be eligable for GC as soon as your classloader itself it.
The only way they could work around this, is to add a reference to one of their objects into one of yours. So you have to be very careful with the API you expose. Another way is if they would make a static reference to their class in a class from another ClassLoader.
I don't see a way to fully automate testing for this. But I suppose you could trace the class unloading with any decent profiler.