views:

1167

answers:

5

At work, we've been having a problem with "PermGen out of memory" exceptions, with the team lead deciding it was a bug in the JVM - something related to hot-deployment of code. Without explaining many details, he pointed out that hot deployment is a "hard problem", so hard that even .NET doesn't do it yet.

I found a lot of articles explaining hot deployment from the bird's-eye-view, but always lacking technical details. Could anyone point me to a technical explanation, and explain why hot deployment is "a hard problem"?

+9  A: 

When a class is loaded, various static data about the class is stored in PermGen. As long as a live reference to this Class instance exists, the class instance cannot be garbage collected.

I believe that part of the problem has to do with whether or not the GC should remove old Class instances from perm gen, or not. Typically, every time you hot deploy, new class instances are added to the PermGen memory pool, and the old ones, now unused, are typically not removed. By default, the Sun JVMs will not run garbage collection in PermGen, but this can be enabled with optional "java" command arguments.

Therefore, if you hot deploy enough times, you will eventually exhaust your PermGen space.

If your web app does not shut down completely when undeployed -- if it leaves a Thread running, for example -- then all of the Class instances used by that web app will be pinned in the PermGen space. You redeploy and now have another whole copy of all of these Class instances loaded into PermGen. You undeploy and the Thread keeps going, pinning ANOTHER set of class instances in PermGen. You redeploy and load a whole net set of copies... and eventually your PermGen fills up.

You can sometimes fix this by:

  • Supplying command arguments to a recent Sun JVM to enable GC in PermGen and of classes. That is: -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
  • Using a different JVM that doesn't employ a fixed sized PermGen or that does GC on loaded classes

But this will help only if your web app shuts down completely and cleanly, leaving no live references to any of the Class instances of any Class loaded by the Class loaders for that Web App.

Even this will not necessarily fix the problem, due to class loader leaks. (As well as too many interned strings in some cases.)

Check out the following links for more (the two bolded ones have nice diagrams to illustrate part of the problem).

Eddie
Eddie -- isn't the reason for keeping the classes though because there are already existing objects knocking around with the "old" class definition?
Neil Coffey
@Edie: Most of the links are related to memory rather than classloader architecture which would be most useful to understand why hot-deploy is a problem. The memory problem is a consequence of the workarounds.
OscarRyz
Just a note about running threads: when I left a thread to sleep over re-deploy by mistake, the moment the thread wake up it thrown a NoClassDefFound (classes were undeployed), and then (of course) died. After it's death PermGen should be OK to be GCed.
Vladimir Dyuzhev
@Vladimir Dyuzhev: Yes, once the Thread dies (and assuming there are no more live references to the Class objects) the Class objects should be GCable in PermGen, if you have it enabled.
Eddie
+1  A: 

The problem in general terms is the security model of Java that actually attempts to prevent that a class that has already been loaded be loaded again.

Of course Java since the beginning has supported dynamic class loading, what it is difficult is class re-loading.

It was consider harmful ( and for a good reason ) that a running java application got injected with an new class with malicious code. For instance a java.lang.String cracked implementation comming from the internet , that instead of creating string, deletes some random file hile invoking the method length().

So, they way Java was conceived ( and I presume .NET CLR in consequence, because it was highly "inspired" in JVM's ) was to prevent an already loaded class to load again that same VM.

They offered a mechanism to override this "feature". Classloaders, but again the rules for the class loaders was, they should ask permission to the "parent" classloader before attempting to load a new class, if the parent has already loaded the class, the new class is ignored.

For instance I have used classloaders that load a classes from LDAP or RDBMS

The hot deploy becomes a necessity in the Java world when the application server became mainstream for Java EE ( and also create the need for micro containers like spring to avoid these kind of burden ) .

Restarting the whole app server after every compile drives anyone crazy.

So app server provider, offer this "custom" class loaders to help hot deployment, and using a configuration file, that behavior, SHOULD be disabled when set in production. But the tradeoff is you have to use tons of memory in development. So the good way to do this is restart every 3 - 4 deployments.

This doesn't happen with other languages that were designed from the beginning to load their classes.

In Ruby for instance, you can even add methods to a running class, override a method at runtime or even add a single method to an unique specific object.

The tradeoff in these kinds of environments is of course memory and speed.

I hope this helps.

EDIT

I've found this product some time ago that promises that reload is make as simple as possible. I didn't remember the link when I first wrote this answer, and I do.

It is JavaRebel from ZeroTurnaround

OscarRyz
what a mess in your head, eh? so java wasn't designed to load classes at runtime, uh? that's why it has Class.forName() from the very beginning?
Vladimir Dyuzhev
That isn't what Oscar wrote Vladimir. He wrote that Java wasn't designed to replace classes at runtime.
Zan Lynx
ClassLoader class is there from version 1. Not designed to replace classes at runtime? Besides, security has nothing to do with PermGen OOM. The limit on PermGen is just a nasty implementation detail of Sun JVM.
Vladimir Dyuzhev
Java has a security model where one can choose to prevent some of what you're talking about, but Java has always been able to dynamically load classes.
Eddie
Hey!! I NEVER said Java wouldn't load classes at runtime! What I said, is: "...to prevent an already loaded class to [be] load[ed] again...". Please learn to read ( and I promise fix my writing ). @Valdimir: Try re-loading java.lang.String with your Class.forName(), you totally misread the question
OscarRyz
The whole point was "hot-deploy" that involves classes reloading. PermGen is not the topic here. Again read the original question: "..why hot deployment is "a hard problem"?.." So any information on PermGen is and additional information. My answers attempts to explain why is that a hard problem.
OscarRyz
OK, got it. It's just not very clear from the text. :-) You start right from security as if it's the main/only reason for trouble.
Vladimir Dyuzhev
A: 

Sun JVM has PermGen space fixed, and eventually it's all consumed (yes, apparently due to a bug in classloader-related code) => OOM.

If you can use another vendor's JVM (e.g. Weblogic one), it dynamically extends PermGen space, so you'll never get permgen-related OOM.

Vladimir Dyuzhev
Wait there. This is not 100% true. The perm gem problem not only related to the JVM and its libraries. Bad application can also cause PermGen errors. Also, dynamically expanding PerGen it is absolutely diffrente from solving it. Wait enough time in any VM and the problem will happen.
Antonio
Correct. Still, dynamic PermGen allows you to survive times more hot deployments. In Sun JVM it often happens on redeployment #1 :-E
Vladimir Dyuzhev
A: 

Which version of java are you using? There were bugs in early Sun 1.4.2, but it's been working for a long long time.
BTW, how will you break the news to your team lead? Are you the team lead?

Ron
It's actually new problem since 1.5. Or at least I ran into it in 1.5 only.
Vladimir Dyuzhev
We're running into this problem with 1.6.I'll probably "break this" to my team lead by sending him a link to this page :-P
Andrey Fedorov
A: 

This is quite an info on Memeory outage issues. I have an issue where my Static contents throw NULL POINTER exception after HOT Deployment. Will enabling GC remove old Static Contents and re-initialize new ones. Or is there some other way to deal with this issue.

Also can we specify the order to Shut down Servlets, classes etc during hot Deployment ?

Thanks in advance Saquib