I am IT systems consultant, an application developer and designer specialized on backend systems, business process automation, performance engineering, SOA and grid technologies. Current development focus on: application of cloud computing in the enterprise - IaaS, SaaS, PaaS and *aaS. http://www.linkedin.com/in/panzin Alex(JAlexoid) has posted 1 posts at DZone. You can read more from them at their website. View Full User Profile

Class Loading in Java: Time to Add Dynamicity?

  • submit to reddit

Class loading. The essential part of the Java world, but why is it so rigid and cumbersome?

Where are we now.

Every time we start Java, the ClassLoader is the essential part that drives the startup process.
Every single piece of code that you have ever written for Java is handled by some ClassLoader.

Your usual ClassLoader hierarchy looks like in the sample diagram:

Sample ClassLoader HierarchyThough, if your application is basic enough, you will not have any application class loaders and their derivatives.

When you deploy your Java EE or WEB application to a Application Server, your code usually runs having several ClassLoaders over it..

The ClassLoader is essential in defining a Class. Basically, a class lives attached to a ClassLoader. That is both a good and a limiting feature:

  • The main positive thing is that we can have multiple versions of the same class without conflicts
  • The main negative thing is that we need to remove the whole ClassLoader (along with all loaded classes) to reload our changes.
But these 2 points are not mutually exclusive.

It's been with us for a very long time. We are actually used to it in it's current state.

Intermediate solutions available to us.

That is where tools like ZeroTurnaround's JavaRebel get "on stage". Reloading of classes while the VM is running is a nice feature. But not everything can be reloaded by JavaRebel: No reloads with class hierarchy change are possible.

In Java 5 Instrumentation API was added for developers to use. Instrumentation API is great, but it does have a little problem: no schema changes are allowed. That means that most of your changes will need the «old» process.

Where can we source our ideas from?

Our «irritating little» friend Ruby has this idea of open classes: you may change a class at runtime by adding new methods. This proves that it's possible to do ad-hoc changes.

PHP deployment is much less hassle than Java deployment. Though the model is not directly applicable to Java, the idea that you only need to change 1 file in an application and your changes are picked up instantly.

What would be useful?

Java(and Java EE) deployment lifecycle is criticized a lot. It's long. Very long. And the compile time is not the main factor here, it's the deployment itself. With the current need to trash the whole ClassLoader hierarchy we are definitely taking too much time and memory consumption(resource usage) does suffer.

Every single (re-)deploy goes through the same procedure on the lowest level:

  • Application specific unload operations
  • Remove any references to the ClassLoader(s) of the application
  • Create a new ClassLoader
  • Link the ClassLoader to the deployed code
  • Application specific load operations

And this is an example where I just added a new logging method and a few statements to a class. As you look at it you might think what a sad state we are in. And if you have a thread there, guess you will have to restart the JVM to get rid of the old code from the memory.

Unload class?

Is it time we had a new method in ClassLoader that would unload a class(ClassLoader.undefineClass)? Well if that would be too hard...

Reload class?

At least, I say. I mean, the dynamic languages had that forever. PHP is a language that has a lot of inexperienced developers, and they still rarely manage to shoot themselves with that "feature". Does everyone consider everyone in Java land an idiot that has to be constricted in every possible way?

Imagine a world....

  • Where you don't do lengthy deployments
  • Where all you do is copy your jar, and the application server determines witch class changed and reloads ONLY it.
  • Where HotFix is easy, and is not a sales feature

I am NOT an expert in JVM internals, but how hard is it to change the piece of data in memory? Java classes are just data in the memory, like everything else. (JVM Spec)

So what do you think? Is it time we have an ability to change the bytecode more dynamically? To have the classes reloaded through ClassLoader? Or, at least, the Instrumentation API would have the restriction on schema changes removed? What are your opinions and thoughts?
20080525_cla_loaders.png15.82 KB
Published at DZone with permission of its author, Alex(JAlexoid) Panzin. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)


Jan Hlavatý replied on Thu, 2008/05/29 - 7:32am

LOL that would be slow as... Groovy ;)


Honey Monster replied on Thu, 2008/05/29 - 11:16am in response to: mike

[quote=monotone]It sounds like what you're saying is that as long as you only change classes in .net that are frequently disposed of, then you're OK. You're saying it maintains the old versions along with the new versions (not mixing the two) until the old ones are no longer used. Then when nothing is using the old class, it permanantly unloads it. Correct? So, if you change several classes including one for an object that lives for the life of the server; then essentially, no classes get reloaded in practice. The eternal class will always be the old version and if all of it's objects are spawned from it, it must hold onto the old versions. Correct?[/quote]

No, that not how .NET (IIS) works. I can change anything. I can upload compiled assemblies (to the /bin folder) or source code to the App_Code directory (will be compiled automatically by the server) or new pages templates/codebehind anywhere (will be parsed and compiled by the server automatically). Some changes will trigger a recycle of the entire appdomain, essentially reloading everything.

For some other changes which are guaranteed to not have longer lasting references pointing to them, the server will simply compile a new assembly an load in addition to the (now outdated) older assembly. This latter process goes for ASP.NET pages - which are modeled with classes - because each page sits in a seperate assembly.

The upshot is that this model supports exactly what the original poster requested: An amazingly simple deployment model where you just upload compiled files, source code files (the "script" feeling), configuration files, resource files or even edit the configuration or templates in-place. You never restart the server. If nessecary the server itself spins up a new appdomain for new requests before unloading the old. The "optimization" that it will not recycle for simple page template/code changes is merely a convenience.

mike replied on Thu, 2008/05/29 - 1:06pm

Then I'm missing something. I'm very ignorant of .net, so excuse me if this is a dumb question. How is .net supposed to reload my class if I've completely changed the class structure (member variables)? How does it know what to do with them? I can see this for single page requests, but for persistent data?

  Also, a poster suggested that with the source code, an upgrade could be determined programmatically. I suspect this is much more complicated than it sounds. If you change a boolean to a tri-state enum, how is parsing the source code going to help you set the new value? You'd have to retain EVERY object's state when the decision was made to set the original value so you could determine the new correct value (assuming that some flags are based on complex data). And in addition, the value may have changed repeatedly based on outside events -- which requires more state tracking. In addition, based on the value, the object may choose to listen for other events -- that it never received because the new value didn't exist in the old code.

  Laslty remember, you're changing a class to fix bugs as well as add new features. The new code may know what to do to correct the problem, but it doesn't necessarily know how to cleanup the old problem once it occurs. Hence, an upgrade mechanism is required.

Honey Monster replied on Thu, 2008/05/29 - 3:05pm in response to: mike

Mike, .NET/IIS can play the trick with pages because pages are compiled into seperate assemblies which can not be referenced from "central" code. Pages are the leafs, so to speak. And because instances of page classes are temporary in nature (bounded by the request), the server can just load the new class (aseembly) if it changes and use it from there. There cannot possibly be instances of it floating around (unless you seriously bend backwards to violate the paradigm - in which case I really don't know what will happen).

For virtually every other change (configuration, global resources, shared assemblies, source code etc) the server will "restart" the entire application. But it will do so in a way that does not interrupt the service: It will spin up a new appdomain and let it handle all requests from there on. It will then wait for any running requests in the old appdomain to complete before killing it off.

When the appdomain is recycled this way will of course lose all memory, except for session storage if you have it configured to be served by a seperate server. Everything that goes into the session this way has to be serializable, and like Java, .NET serialization does have rudimentary versioning support. So, the important state (session) can be retained with no or relatively little effort; even on a production system.

The server plays a few more tricks. Rather than loading assemblies from the the app directory directly, it will copy them to a private cache and load them from there. That way the files will not be locked in the app directory and thus will allow you to replace them. Furthermore it will keep a cache of the JITed assemblies (fully compiled), so even if you change/upload one assembly it will not have to go through a full recompile of all assemblies. The server continously watches for file changes in the app directory, you do not need to inform it when you change a file; it will pick up on it itself.

The configuration is hierarchical and (initially) based on a single file. If you wish you can tear out config sections into seperate files. Because the files are referenced from the central config file the server can set up change notifications for those as well.

As I said, it works remarkably well. It is very responsive and you do not have to package or fully deploy at all. You just change what needs to be changed and re-request the page. You can even cowboy code with notepad directly on the server, if you so wish. No tools needed.

Alex Blewitt replied on Sat, 2008/05/31 - 9:47am

Perhaps you've been living under a rock and haven't heard of OSGi. That's exactly what OSGi allows you to do ...

Alex(JAlexoid) ... replied on Sat, 2008/05/31 - 12:28pm in response to: Alex Blewitt

I guess you don't undestand the issue or you have little idea what OSGi is for.

mike replied on Sat, 2008/05/31 - 1:50pm

@Uffe Seerup. I think what you described was what I was trying to convey. This works for many (perhaps most) simple changes. The serialization process is the upgrade mechanism, however, this limits what you can do since serialization limits what objects you have access to (if you’re fixing a bug by adding new flags who's initial value come from another object for instance), but you’re right, that probably covers most web servers. It’s not a 100% solution, but does get you there for many things.

@Alex Blewitt. While I agree OSGI could be used to solve this issue, doesn’t OSGI have some pretty massive overhead, both in complexity, and a certain amount of run-time costs (not constant run-time costs, but there are costs to it’s dynamic nature)? We explored it and decided it was overkill for us.

Netifera Platform replied on Sat, 2009/04/25 - 7:28pm


Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.