Webapp classpaths and classes being loaded into heap - java

If I have two webapps, both of which have the same third party library jars in their web-inf/lib directories, say log4j.....when the first webapp is loaded and a log4j class is created, this class is loaded into the heap. When the second webapp is loaded and tries to load a log4j class, will it find the class in the heap and use that one? Or will it load its own copy of the class into the heap?

Hmm I think it is mostly a ClassLoader problem here, it still depend of the application server you are using, but I guess most of them use a single JVM and reserve a ClassLoader per running webapp so that you can have different webapp with different version of the same jar/clases running alltogether.
In tomcat for instance, if you need to have some shared libraries, you can use the /tomcat/shared/lib folder where you put all the jars that will be accessible by all your webapps.
Otherwise yes, different webapp won't share the same heap, it would mean webapp could access object created by other webapp running in the same application server

No, it shouldn't.
The fact classes are loaded on the heap mean nothing here. as each class loader maintains its own list of classes it loaded.
However, Classloaders are also organised into a tree and they are supposed to ask their parent classloaders to attempt to load the class first, as described in the javadoc of the ClassLoader class.
The ClassLoader class uses a delegation model to search for classes and resources. Each instance of ClassLoader has an associated parent class loader. When requested to find a class or resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself.
However, webservers typically don't follow this delegation model, to avoid libraries used by the webserver itself being picked up by webapps. (This behaviour is sometimes configurable, but it depends on the webserver you're using.)
So in practice every webapp should have its own separate class space, independent of all the other webapps, therefore they can even use two different versions of the same library without any problems.
The other important lesson is that the same class file loaded by two different class loader will actually be two separate classes in the heap and objects from one class will not be compatible with the other class.

Related

How Tomcat Classloader separates different Webapps object scope in same JVM?

Since Tomcat can load more than one webapp at once, and those webapps can work separately, and do not disturb each other, and they work in same JVM.
So I am very confused about how tomcat handle The Object scope in the same JVM.
For example I have a singleton object in both of the two different Webapps, and tomcat will generate two different singleton Object for each. I always thought that the singleton object have only one object in the same JVM, but in tomcat JVM there maybe has two or more.
I have read some info about the ClassLoader, Tomcat has its own WebAppClassLoader to load webapps. So does it mean the Object Scope here is the ClassLoader or am I wrong. Does anyone know about this or can give me some info about tomcat work memory layout?
All the secrets is behind those ClassLoader instances.
The state of the class (like all static variables, byte code and so on) is scoped by the class loader which loads that class (a class is identified in JVM by its fully qualiflied name and the class loader loading the class. This is not exactly a scope, but thinking as scope usually helps understanding this better).
So if a class is loaded by two different class loaders, this class exists twice within the VM, it has two sets of static fields, can have different byte code (like different method implementations) and all such. Note that these two objects cannot be cast to each other even their names are identical.
"Normal" Java applications have all classes loaded by a class loader hierarchy and every class is only loaded once.
For more complex scenarios, you will need different behaviours. Sometimes you want to isolate a library from messing with your code (like plugins in eclipse or web applications in an application server).
The basic idea to isolate your program from other classes is to load those with an extra class loader and use a lot of reflection. If you want to read up on this have a look at Oracle's documentation on ClassLoaders or OSGI.
Tomcat (and a lot of other web containers / application servers) load the application with separate ClassLoader hierarchies. This isolates all classes against other (web) applications and thus also makes sure, that singletons, different class versions and all this stuff does not collide.
Remember that a class in Java is identified by its fully qualified name and the classloader that loaded it. Tomcat uses separate classloaders for each context (web application) that you deploy, thus keeping them separate. In addition, the system classloader loads the tomcat specific libraries and JVM bootstrap loader load the Java core libraries.
In normal Java applications when a classloader is asked to load a class it forst delegates the request to it's parent class loader and then loads it if parent class loaders cannot find the requested class.
For web application servers this slightly differs. There are generally different class loader for each web app deployed in a web application server like tomcat. For Tomcat it looks like below -
So for web apps class loading resource happens in following order -
Bootstrap classes of your JVM (Core java classes)
/WEB-INF/classes of your web application
/WEB-INF/lib/*.jar of your web application
System class loader classes (Tomcat / Classpath specific classes)
Common class loader classes (classes common to all web apps)
But note if web application class loader is configured with delegate="true" then order is changed -
Bootstrap classes of your JVM (Core java classes)
System class loader classes (Tomcat / Classpath specific classes)
Common class loader classes (classes common to all web apps)
/WEB-INF/classes of your web application
/WEB-INF/lib/*.jar of your web application
For more details you can check Apache Tomcat's Class Loader HOW-TO page.
One thing that always gets left out when talking about singletons, is that a singleton can have only one instance per classloader. A ClassLoader limits class visibility, so the same class can exist under several different classloaders in the same VM. This allows you, among other things, to have different versions of jars loaded at the same time.
This question: Java Class Loaders seems to have some nice links and resources for further studying.
The "ID" of a class in the JVM consists of the fully qualified class name and the class loader that was used to load it. This means, if you load two classes with the same name by different class loaders they are considered different classes.
So a singleton would be singleton for a classloader - in a container/JVM; as a container/JVM might have multiple classloaders.
Different App in tomcat using different classloader to seperate. For example app1 using ClassLoaderA, app2 using classloaderB.
Each class will use its own classloader to load other classes. So if ClassA.class references ClassB.class then ClassB needs to be on the classpath of the classloader of ClassA, or its parents. For example In app1, com.exmaple.test1 loaded from ClassLoaderA. And com.exmaple.test1 want to new com.exmaple.test2(). By default It use its own classloader ClassLoaderA to load com.exmaple.test2. So In the view of com.exmaple.test1 it can only see its own classpath's class(app1/webapp/classes or app1/webapp/lib). And In app2, It will see a different view.
In summary learn classloader you must understand the delegation model. And the visibility is the child can see the parent. but the parent can not see the child and the sibling can not see the sibling. So we can isolate different app.

Singleton across JVM or Application instance or Tomcat instance

If I deploy and run 2 instances of same application on a single instance of Tomcat(Or any other server). Then a single object(of a Singleton class) would be created:
Across single instance of Tomcat (but common for 2 instances of same application) OR
Across application instance (different for 2 instances of application)
So essentially I want to understand that is it always a case that a single object of Singleton class gets created per JVM? How does this works in case of application hosted on a Web server(or container).
If you have a singleton class and you run two webapps that use this class in Tomcat both webapps will get 2 different instances of this singleton in JVM running the Tomcat.
But if your webapp will use a singleton from JRE or Tomcat shared libs, eg Runtime.getRuntime webapps will get the same instance of Runtime.
This is because Tomcat uses individual class loaders for webapps. When a webapp class loader loads a class it first tries to find it on webapp class path, if the class is not found it asks parent class loader to load the class.
A singleton is normally tied to a ClassLoader only.
So if you have a singleton based on a .class file in your .war file, and you deploy this web application multiple times, each application gets its own singleton.
On the other hand, if the .class file of your singleton is in the classpath of tomcat, then you only have one instance. This .class does not belong to a specific web application (it belongs to the tomcat instance).
If you have the singleton in both locations, it depends on the class loader hierarchy, and you can possibly select between "parent first" or "web application first".
It is possible to create such a singleton by assuring that you always query the same ClassLoader for the singleton. I wrote an extensive explanation in this other answer.
The Tomcat creates new class loader for each web application.
So if your Singleton class is stored in war file, the same war file will have two instances in Tomcat container i.e. it creates two separate Singleton class for each war file.
If the Singleton class is in Tomcat's share library path, Tomcat creates only one Singleton instance for the both application.
JVM analogy:
JVM is like big mansion. It contains combined family with serveral applicance and libraries.
ClassLoaders are family members, each family member represents one ClassLoader (works as delegate hierarchy not inheritance hierarchy). Note: ClassLoader is class, it can create multiple instances.
Applications are like appliance. for example: Washing Machine, Fridge, Air Cooler, Television, Dining table, Sofa and so on...
Libraries are each one having his own individual library. Every one search in parent's library if not found then search in his own library.
limitations:
If father buy an appliance their children can use it, but it can not used by his parent and siblings.
Each application might use different versions of the same libraries. i.e. If library contain two or more versions of same books, it picks whichever the book is available first.
Each family number can use only one unique appliance.
In home, we can use multiple appliance of same version. So, JVM allows us to run multiple applications of same versions.
Garbage Collector is a servant in Mansion, who roams as a daemon, who can clear any kind of Objects.
The scope of a static variable is limited to one per ClassLoader.
<shakey-ground>As far as I know, a singleton is unique per classloader. So I think the answer to your question depends on the way the container loads the web application.
If it allocates one classloader per web app, then it seems like you would get two, completely independent, singleton objects. If it allocates one classloader and all web apps use it, then they share the same singlet one instance.</shakey-ground>

How does class loading work when the same class exists in different applications on the same server?

I have multiple web-apps running on an app server and each web-app WAR file contains a copy of the same jar file.
Does this mean that a class in that jar file will be loaded multiple times in the JVM, once for each WAR file it exists in? Following on from that, if I have a static synchronized method in such a class, is it only synchronized among threads within the web-app it exists in but not synchronized against the same method in the same class in a different jar file in a different WAR file? (Hope the question makes sense, will clarify if necessary).
If this is the case I presume the best solution is to remove the jar file from each WAR file and deploy it to a shared classpath folder on the server?
A Java classloader typically works by looking for classes in one or more places in a fixed sequence. For instance, the classloader that loads your application when you run it from the command line looks first in the rt.jar file (and others on the bootclasspath), and then in the directories and JAR files specified by your classpath.
A webapp classloading is similar in principle, but a bit more complicated in practice. For a particular webapp, a webapp's classloader looks for classes in the following order. For example Tomcat 6 looks for classes in this order:
Bootstrap classes of your JVM
System class loader classes (described here)
/WEB-INF/classes of the webapp
/WEB-INF/lib/*.jar of the webapp
$CATALINA_HOME/lib
$CATALINA_HOME/lib/*.jar
Of course, once the classloader has found the class it is looking for, it looks no further. So classes with the same name later in the order won't get loaded.
The complication is that the web container has one classloader for each webapp, and these classloaders delegate to other classloaders that manage the common classes. In practice, this means that some classes will only ever be loaded once for the entire container (e.g. 1. and 2.) and others may get loaded multiple times by different classloaders.
(When a class is loaded more than once, it results in distinct Class objects and distinct class statics. The versions of the class are different types as far as the JVM is concerned and you cannot typecast from one version to the other.)
Finally, Tomcat can be configure to allow individual webapps to be "hot loaded". This entails stopping a webapp, creating a new classloader for it, and restarting it.
FOLLOWUP
So ... synchronizing a static method will not protect access to a shared resource where the class has been loaded multiple times?
It depends on the details, but it probably won't. (Or to look at if another way, if a class has actually been loaded multiple times, then a static method of each "load" of the class will access a different set of static fields.)
If you really want a singleton application class instance to be shared by multiple webapps in the same container, it is simplest if you put the class into $CATALINA_HOME/lib or the equivalent. But you also should ask yourself if this is good system design. Consider combining the webapps, or to using request forwarding etc instead of a shared data structure. The singleton pattern tends to be troublesome in webapps, and this flavor is even more so.
Java EE application servers typically use multiple classloaders to isolate applications from each other, and allow new versions of one application to be deployed without affecting other apps.
You get patterns such as several WAR files and one EJB file in an EAR with a hierarchy of classloaders, each WAR having it's own.
This does lead to duplication as you describe, but this is not necesserily a bad thing. It means that you can even have different versions of the same JARs deployed a the same time, and that may actually be benficial, allowing incremental migration to new versions.
Some application servers (WebSphere for exmaple) have explicit support for a shared library concept, and I do use that.
Be wary of just popping JARs into arbitrary classpaths, you run the risk of destabilising the app server itself.
Most application server use most specific along a path takes precedence policy.
If you have multiple library that do the same thing, You should consider to put them inside application server lib (f.e: TOMCAT_HOME/lib)

How to remove a loaded class from classloader? [duplicate]

I have a custom class loader so that a desktop application can dynamically start loading classes from an AppServer I need to talk to. We did this since the amount of jars that are required to do this are ridiculous (if we wanted to ship them). We also have version problems if we don't load the classes dynamically at run time from the AppServer library.
Now, I just hit a problem where I need to talk to two different AppServers and found that depending on whose classes I load first I might break badly... Is there any way to force the unloading of the class without actually killing the JVM?
Hope this makes sense
The only way that a Class can be unloaded is if the Classloader used is garbage collected. This means, references to every single class and to the classloader itself need to go the way of the dodo.
One possible solution to your problem is to have a Classloader for every jar file, and a Classloader for each of the AppServers that delegates the actual loading of classes to specific Jar classloaders. That way, you can point to different versions of the jar file for every App server.
This is not trivial, though. The OSGi platform strives to do just this, as each bundle has a different classloader and dependencies are resolved by the platform. Maybe a good solution would be to take a look at it.
If you don't want to use OSGI, one possible implementation could be to use one instance of JarClassloader class for every JAR file.
And create a new, MultiClassloader class that extends Classloader. This class internally would have an array (or List) of JarClassloaders, and in the defineClass() method would iterate through all the internal classloaders until a definition can be found, or a NoClassDefFoundException is thrown. A couple of accessor methods can be provided to add new JarClassloaders to the class. There is several possible implementations on the net for a MultiClassLoader, so you might not even need to write your own.
If you instanciate a MultiClassloader for every connection to the server, in principle it is possible that every server uses a different version of the same class.
I've used the MultiClassloader idea in a project, where classes that contained user-defined scripts had to be loaded and unloaded from memory and it worked quite well.
Yes there are ways to load classes and to "unload" them later on. The trick is to implement your own classloader which resides between high level class loader (the System class loader) and the class loaders of the app server(s), and to hope that the app server's class loaders do delegate the classloading to the upper loaders.
A class is defined by its package, its name, and the class loader it originally loaded. Program a "proxy" classloader which is the first that is loaded when starting the JVM. Workflow:
The program starts and the real "main"-class is loaded by this proxy classloader.
Every class that then is normally loaded (i.e. not through another classloader implementation which could break the hierarchy) will be delegated to this class loader.
The proxy classloader delegates java.x and sun.x to the system classloader (these must not be loaded through any other classloader than the system classloader).
For every class that is replaceable, instantiate a classloader (which really loads the class and does not delegate it to the parent classloader) and load it through this.
Store the package/name of the classes as keys and the classloader as values in a data structure (i.e. Hashmap).
Every time the proxy classloader gets a request for a class that was loaded before, it returns the class from the class loader stored before.
It should be enough to locate the byte array of a class by your class loader (or to "delete" the key/value pair from your data structure) and reload the class in case you want to change it.
Done right there should not come a ClassCastException or LinkageError etc.
For more informations about class loader hierarchies (yes, that's exactly what you are implementing here ;- ) look at "Server-Based Java Programming" by Ted Neward - that book helped me implementing something very similar to what you want.
I wrote a custom classloader, from which it is possible to unload individual classes without GCing the classloader. Jar Class Loader
Classloaders can be a tricky problem. You can especially run into problems if you're using multiple classloaders and don't have their interactions clearly and rigorously defined. I think in order to actually be able to unload a class youlre going go have to remove all references to any classes(and their instances) you're trying to unload.
Most people needing to do this type of thing end up using OSGi. OSGi is really powerful and surprisingly lightweight and easy to use,
You can unload a ClassLoader but you cannot unload specific classes. More specifically you cannot unload classes created in a ClassLoader that's not under your control.
If possible, I suggest using your own ClassLoader so you can unload.
Classes have an implicit strong reference to their ClassLoader instance, and vice versa. They are garbage collected as with Java objects. Without hitting the tools interface or similar, you can't remove individual classes.
As ever you can get memory leaks. Any strong reference to one of your classes or class loader will leak the whole thing. This occurs with the Sun implementations of ThreadLocal, java.sql.DriverManager and java.beans, for instance.
If you're live watching if unloading class worked in JConsole or something, try also adding java.lang.System.gc() at the end of your class unloading logic. It explicitly triggers Garbage Collector.

Unloading classes in java?

I have a custom class loader so that a desktop application can dynamically start loading classes from an AppServer I need to talk to. We did this since the amount of jars that are required to do this are ridiculous (if we wanted to ship them). We also have version problems if we don't load the classes dynamically at run time from the AppServer library.
Now, I just hit a problem where I need to talk to two different AppServers and found that depending on whose classes I load first I might break badly... Is there any way to force the unloading of the class without actually killing the JVM?
Hope this makes sense
The only way that a Class can be unloaded is if the Classloader used is garbage collected. This means, references to every single class and to the classloader itself need to go the way of the dodo.
One possible solution to your problem is to have a Classloader for every jar file, and a Classloader for each of the AppServers that delegates the actual loading of classes to specific Jar classloaders. That way, you can point to different versions of the jar file for every App server.
This is not trivial, though. The OSGi platform strives to do just this, as each bundle has a different classloader and dependencies are resolved by the platform. Maybe a good solution would be to take a look at it.
If you don't want to use OSGI, one possible implementation could be to use one instance of JarClassloader class for every JAR file.
And create a new, MultiClassloader class that extends Classloader. This class internally would have an array (or List) of JarClassloaders, and in the defineClass() method would iterate through all the internal classloaders until a definition can be found, or a NoClassDefFoundException is thrown. A couple of accessor methods can be provided to add new JarClassloaders to the class. There is several possible implementations on the net for a MultiClassLoader, so you might not even need to write your own.
If you instanciate a MultiClassloader for every connection to the server, in principle it is possible that every server uses a different version of the same class.
I've used the MultiClassloader idea in a project, where classes that contained user-defined scripts had to be loaded and unloaded from memory and it worked quite well.
Yes there are ways to load classes and to "unload" them later on. The trick is to implement your own classloader which resides between high level class loader (the System class loader) and the class loaders of the app server(s), and to hope that the app server's class loaders do delegate the classloading to the upper loaders.
A class is defined by its package, its name, and the class loader it originally loaded. Program a "proxy" classloader which is the first that is loaded when starting the JVM. Workflow:
The program starts and the real "main"-class is loaded by this proxy classloader.
Every class that then is normally loaded (i.e. not through another classloader implementation which could break the hierarchy) will be delegated to this class loader.
The proxy classloader delegates java.x and sun.x to the system classloader (these must not be loaded through any other classloader than the system classloader).
For every class that is replaceable, instantiate a classloader (which really loads the class and does not delegate it to the parent classloader) and load it through this.
Store the package/name of the classes as keys and the classloader as values in a data structure (i.e. Hashmap).
Every time the proxy classloader gets a request for a class that was loaded before, it returns the class from the class loader stored before.
It should be enough to locate the byte array of a class by your class loader (or to "delete" the key/value pair from your data structure) and reload the class in case you want to change it.
Done right there should not come a ClassCastException or LinkageError etc.
For more informations about class loader hierarchies (yes, that's exactly what you are implementing here ;- ) look at "Server-Based Java Programming" by Ted Neward - that book helped me implementing something very similar to what you want.
I wrote a custom classloader, from which it is possible to unload individual classes without GCing the classloader. Jar Class Loader
Classloaders can be a tricky problem. You can especially run into problems if you're using multiple classloaders and don't have their interactions clearly and rigorously defined. I think in order to actually be able to unload a class youlre going go have to remove all references to any classes(and their instances) you're trying to unload.
Most people needing to do this type of thing end up using OSGi. OSGi is really powerful and surprisingly lightweight and easy to use,
You can unload a ClassLoader but you cannot unload specific classes. More specifically you cannot unload classes created in a ClassLoader that's not under your control.
If possible, I suggest using your own ClassLoader so you can unload.
Classes have an implicit strong reference to their ClassLoader instance, and vice versa. They are garbage collected as with Java objects. Without hitting the tools interface or similar, you can't remove individual classes.
As ever you can get memory leaks. Any strong reference to one of your classes or class loader will leak the whole thing. This occurs with the Sun implementations of ThreadLocal, java.sql.DriverManager and java.beans, for instance.
If you're live watching if unloading class worked in JConsole or something, try also adding java.lang.System.gc() at the end of your class unloading logic. It explicitly triggers Garbage Collector.

Categories

Resources