Tomcat: how does Tomcat unloads classes internally? - java

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

Related

Memory leak not unloading Singletons when bringing down a Java EE application

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).

How to cache objects on Tomcat across several WARs without putting the class-containing JAR into /lib/ext?

How can I cache server-wide (with cache scope spanning multiple WARs on this server) instances of classes from a JAR which is contained binary-identical in several WARs on a web container (server, e. g. Tomcat)?
<EDIT> I want to cache application data across WARs because the data is common to them. (It's a portal project, where it can be useful to share common data across different "views" implemented as different portlets deployed as different WARs, and using a Java object cache is much faster and more simple than using a central data-holding service.) </EDIT>
Is that possible at all? Or is it required to put such a JAR on a path accessed by a common parent classloader, like in /lib/ext ?
See: Java, Classpath, Classloading => Multiple Versions of the same jar/project
See: How does class loading work when the same class exists in different applications on the same server?
See: cast across classloader?
See: What is a serialVersionUID and why should I use it?
Yes, the best option is to put the classes in a class loader that is a parent of the two applications. If by lib/ext you mean JAVA_HOME/lib/ext, then I would not recommend that. Instead, you should put them in CATALINA_HOME/lib directory. See the Shared Library Files section of the documentation, which links to the Class Loader HOW-TO documentation.
You can add common classes (jars) to the shared.loader property in conf/catalina.properties. Those classes are available to all web apps but not tomcat itself.
If you implement a cache around a static singleton, then you would be able to access the objects from different web apps. I don't know if that is best practice however. For example it makes it hard to scale because it makes it impossible to load balance the apps onto many servers.
The answer seems to be "it depends".
If the JAR(s) (or classes) in question do not have dependencies conflicting with other components also deployed on the server, both proposed solutions (CATALINA_HOME/lib/ext/ and CATALINA_HOME/conf/catalina.properties :: shared.loader) should plainly work. Thus both are "correct answers" and I cannot see which one is "more correct" than the other.
However I missed a crucial detail when I first asked the question (but this does not invalidate it): In my case the JAR in question required Spring 4.2.9.RELEASE (and other dependencies), but other relevant WARs deployed on the same server contain and require Spring 3.0.7. (The objects to be cached do not depend on Spring, but the JAR was not designed with this problem in mind, and it also contains other related code depending on Spring which now would be very difficult to separate.)
Generally it should be possible to put into CATALINA_HOME/lib/ext/ what ever you want as long as all already deployed WARs contain everything they need: The "module first / parent last" class loading policy should prevent conflicts, even if (as in this example) Spring 4.2.9 is available to the parent classloader and Spring 3.0.7 is available to the WAR classloader. But it looks somewhat "unclean" and messy to me to mix-up things that way.
Therefore I decided to use the "to-be-cached" object's classloader hash code as the key in a map, in which the cached data are the values. Then all cached data is selected "by classloader" which automatically and transparently ensures assignment compatibility. If there is also another WAR deployed on the server which can change and thus invalidate the cached data, it can remove the whole map from the cache, forcing the "read-access" WARs to reload data on next access.
However this approach DOES NOT allow cross-WAR cacheing: Effectively every WAR will get its own private cache segment.
Another approach would be to deliberately transform all data to cache to/from e. g. JSON so as to get a "naturally global" data type like java.lang.String for the cached data. If chosen from the beginning of the project, to me this seems to be the cleanest way, but if there is already a complex (and generally working) implementation in place, this may cause some work to do.
Comments on this self-answer are welcome!

How can I unit test GC?

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.

Running class in separate context

I'm trying to make a simple application that loads and runs some classes during runtime. For example, let's say I have this config:
module1.classpath=module1.jar,somelibs1.jar
module1.class=com.blabla.Module1
module2.classpath=module2.jar,somelibs2.jar
module2.class=com.blabla.Module2
Then I need to load libraries specified in module1.classpath and run the module1.class with that libraries loaded. Afterwards I need to load module2.classpath and run module2.class with those libraries.
How do I handle the case when somelibs1.jar and somelibs2.jar have the same classes inside? Basically I'd like to run module1.jar using exclusively somelibs1.jar and module2.jar using exclusively somelibs2.jar. How do I implement that?
I'm guessing I need to create a separate classloader for each of my classes and push the jars in that classloaders. However I'd appreciate some example or at least a confirmation that it is a right way to do that.
This seems to be a pretty good use case for OSGI. I would recommend using OSGI for this as everything you nees is provided by OSGI out-of-box.
But if for some reason you can't use OSGI, then what you need to do is to have a classloader for each module. Load the moduleX.class by a ClassLoaderX, and moduleX.classpath should be added in to ClassLoaderX's path. You can use a set of simple URLClassLoader for this.
Thanks for question. Very interesting.
It seems to you can't use several versions of the same class in one instance of JVM. I've never had this task and I don't know how to implement this.
But let's play. I don't know what is exotic application do you develop. May be you can run many JVMs and each JVM will have exclusive CLASSPATH.
Write application which can run (for example using Runtime.exec()) another JVM and make a conversation to it via some channel (may be network).

Java, runtime class reloading

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.

Categories