On different sites , Dynamic class loading is given as one of the reason of permgen problem.
As per my understanding , Dynamic class loading is loading the class as and when it is required.Alonwith that if Class A is loaded and it is referring another class B , it will also be loaded along with that. This is Dynamic class loading. Right? If yes, this is essential and inbuilt feature of JVM. What we can do about it?
Or my understanding is wrong here. when we say Dynamic class loading , are we reffering to custom class loaders here?
My last question related to above is, Class is loaded once by customer loader. So when we do hotdeployment on application server, how appserver loads the new version of class. Does it use different class loader here?
No, dynamic class loading refers to loading classes during runtime that are unknown at compile time, e.g., via Class.forName, or reflection (1, 2).
Related
I am currently reading Class loader and their hierarchy functionality.
If I call below code -
ClassA a= Class.forName("com.test.ClassA")
As per my understanding,now it will be initialized and loaded in memory with help of Application Class loader.
I have below questions:
What will happen if I call again call the above code? Will there be new instance created in memory for 'ClassA' or will it return the same loaded class reference?
If yes, as per this post of javarevisited,"By using separate ClassLoader you can also loads same class from multiple sources and they will be treated as different class in JVM"
What will be use of it?
You will get the same class. Just test it. Load it a second time and check if a1 == a2.
The most frequent usage of this feature is probably in app servers: you can deploy several web applications in a single server, and all can use the same classes. But they shouldn't share static variables. And if one uses class Foo from library 1.0, and the other one uses class Foo from library 2.0, there should be no problem. Hence the need to load the same class with different class loaders.
New instance is created only if you call:
ClassA inst = new ClassA();
If you call Class.forName, the class definition (metadata and bytecode) is loaded into JVM, into special section of managed memory called HEAP. Usually, the applications use this function to preload class into JVM, so that later on there is no latency when application needs it.
The use is hotdeploy for example. You're debugging java web server. You find a mistake, and just want to change (reload) one class, not the whole application. Important point here is also "Different Class Loaders". That means that libraries in java can be loaded from different sources: jar, war (archives), from database, from network. Compare this to COM model of Windows, where library must be in same folder or /system32/ folder.
I'm implementing a feature that requires passing dynamically generated types (in binary representation, serialised with Kryo) between several instances of JVM (over the network). In order to properly resolve what types are loaded and what are not I use a custom system class loader (passed as java -Djava.system.class.loader parameter), which is used by other dynamically created class loaders as a parent. This custom system class loader knows of its children and in case it cannot find a class these derived class loaders can be asked if they have it (this is a reverse to the standard hierarchical structure of class loaders).
These dynamically generated types get transferred and loaded between different JVMs perfectly fine. The problem arises when I try to deserialise an instance of some type (a corresponding class is loaded from disc and is identical for all JMVs) that references one of the dynamically generated types -- ClassNotFoundException is raised by an instance of Kryo, which tries to readClass by name of the dynamically generated type.
Inside method readClass there a call to Class.forName, which in turn does not use the specified custom class loader (that knows of all dynamically generated types) and instead uses sun.misc.Launcher$AppClassLoader instance.
Is it possible to specify a custom system-wide class loader, so that all classes are loaded with it in order to avoid the described problem?
Update
Further analysis revealed that ClassLoader.getSystemClassLoader() actually returns the specified custom system class loader. Fortunately, the Kryo library supports setting of a custom class loader specifically for loading classes upon deserialisation. These two facts formed the basis of a solution to the described problem.
How would you load the custom class loader if all classes have to laoded using that class loader?
One way to get around this is to create a native instrumentation agent. This is loaded before any classes are loaded.
Another way around it is to compile your own version of AppClassLoader and prefix it to the boot class path or add it to the libs/endorsed directory.
I have an application that needs the ability to update parts of itself (one class at a time) without stopping and restarting. With the JavaCompiler API, it is straightforward to generate modified class source code, recompile, load, and instantiate a class. I can do this all in memory (no files read from disk or net).
The application will never instantiate more than one object of such a class. There will only be two or three references to that object. When the modified class is loaded and instantiated, all those references will be changed to the new object. I can also probably guarantee that no method in the affected class is running in another thread while loading the modified class.
My question is this: will my class loader have problems loading a modified class with the same name as a class it previously loaded?
If I do not explicitly implement a cache of loaded classes in the class loader, would that avoid problems? Or could delegation to a parent class loader still cause a problem?
I hope to use a single instance of my class loader, but if necessary, I could instantiate a new one each time I update a class.
Note: I looked at OSGI and it seems to be quite a bit more than I need.
There's a useful example on this at http://tutorials.jenkov.com/java-reflection/dynamic-class-loading-reloading.html
We do quite a bit of dynamic class reloading ourselves (using Groovy for compilations). Note if you've got class dependencies then you may need recompile these dependencies on reload. In dev stacks we keep a track of these dependencies and then recompile whenever dependencies become stale. In production stacks we opted for a non-reloading ClassLoader and create a new ClassLoader when ever anything changes. So you can do it either way.
BTW - you might find the GroovyScriptEngine at http://grepcode.com/file/repo1.maven.org/maven2/org.codehaus.groovy/groovy-all/1.8.5/groovy/util/GroovyScriptEngine.java#GroovyScriptEngine very interesting if you want to dig around how they do it.
Okay, it should work: when you load the new class, it will replace the class name in the appropriate tables, and the memory should be GC'd. That said, I'd give it a strenuous test with a real short program that compiles a nontrivial class and replaces it, say 10,000 times.
I am aware that using proxy capable libraries (javassist, JDK dynamic proxies, etc) that it is possible to enhance a class to implement an interface at runtime.
My question is: is it possible to enhance an instantiated object to implement an interface at runtime (and likewise provide appropriate method handlers).
No, we can't change a class that has already been loaded. And we can't replace a loaded class (within a classloader).
There may be a chance if you
load a class with a custom classloader
unload the classloader (should unload the class aswell)
load the modified class again with a new classloader instance
But that is very, very black magic...
I am doing a JBoss SEAM project and when I view a form I get this error.
java.lang.ClassCastException:
it.cogitoweb.csi.entity.csiorelav.CsiTipoLav cannot be cast to
it.cogitoweb.csi.entity.csiorelav.CsiTipoLav
Its alway the same JPA class which is related to the form which is shown on the screen, it doesn't make sense to me why is it the same class, it seems impossible.
This happens when two different ClassLoader objects load classes with the same name. The equality of two classes in Java depends on the fully qualified name and the class loader that loaded it.
So if two independent class loaders load classes from the same location, then objects of those types will not be able to be cast to each others type, even if their classes are called the same.
As Joachim explained earlier, java.lang.ClassCastException typically occurs when two classloaders load the classes with the same name. However, i have come across another situation when this could occur.
This could occur with some IDE's that automatically reloads classes that have been modified. In such cases there might be older versions of the class retained in memory causing ClassCastException.
Here are a few ways you could resolve this issue :
If you are writing a custom class loader, while loading a class make sure that the base/default class loader does not already have an instance of that class loaded.
Make the class being loaded a sub-class of the class that is already loaded by the default class loader.
Make the class being loaded implement an interface that is already loaded by the default class loader.
More info here - http://www.jspwiki.org/wiki/A2AClassCastException
This is because the class has been loaded by two different classloaders. You cannot cast between them.
You've likely got a duplicate copy of CsiTipoLav in your application, and the two different copies are being loaded at different times from different classloaders. JBoss has a plethora of different classloaders in a hierarchy, and it's easy to get things in a twist.
Make sure you only have one copy of the class.
The object you are trying to cast, is loaded by a different classloader than the one which has loaded the class you are trying to cast into.
In my case i had two different *.ear and wanted to load a class from the other.
So i had to isolate the classloader. I used this description:
http://www.thorgull.be/wiki/index.php?title=ClassLoader_isolation_in_JBOSS
It worked for me.