You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by Brian Munroe <br...@gmail.com> on 2007/09/07 02:39:14 UTC

Garbage Collection and Class unloading

Can someone explain a little bit about classloading really quick?

Let me preface this with: I am maintaining an application which I did
not develop.

Looking at the WEB-INF/lib directory, it has around 76 different jar
files, some actually used in the application, some (well, most) not.
They either pertain to legacy features or are functionality duplicate
(two different versions of Oracle driver libraries, for example)

I am trying to tune Tomcat because it keeps running out PermGen space,
so I am using jconsole to inspect the JVM.  I suppose it isn't really
a profiler, but it is a start.

According to jconsole, after doing many application development cycles
of remove->deployment of *.war to Tomcat (via manager), it looks like
as many as 20k classes are loaded.  I was under the impression that
the garbage collector would unload classes as necessary.

I tried to force a GC via jconsole, it reduced the heap memory like it
should, and it unloaded a few classes pertaining to reflection, but
nothing like what I was hoping for.  I then leave it be for several
hours, and all magic like, the GC unloads about 4k classes.

First question.   Anyone tell me why it doesn't unload classes when I
am trying to force it?  Is classloading/unloading not even the same as
garbage collection?

Second question.  Is having 20k classes loaded normal for a middle
sized application?  I am assuming if I remove all the unnecessary jars
from WEB-iNF/lib I can reduce that number?  Would it benefit anything
to place them in shared/lib?

Third:  If over 75% of the classes in the jars aren't being called
anywhere in the application, even though they get loaded on the
initial application deployment, shouldn't the GC unload them almost
immediately, since there aren't any open resources using these
classes.

Fourth question:  Do my JAVA_OPTS looks decent?

JAVA_OPTS="-Xms512m -Xmx512m -server
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=8114
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-verbose:gc
-XX:+PrintClassHistogram
-XX:+PrintGCDetails
-XX:MaxPermSize=128m"

many thanks!

-- brian

ps.  My platform looks like:  Solaris 9 (SPARC), Tomcat 5.5.23, JDK
1.6.0_02 (32-bit)

---------------------------------------------------------------------
To start a new topic, e-mail: users@tomcat.apache.org
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Garbage Collection and Class unloading

Posted by Brian Munroe <br...@gmail.com>.
On 9/6/07, David Smith <dn...@cornell.edu> wrote:


> I'd think your best bet is to clean out all the dead
> in-house code and then thin out the dependencies until it stops
> building.  If nothing else, refactor your code to pair down the multiple
> versions of libraries.
>

Oh, don't you worry, me and the original developer are gonna have a
code audit come Monday!  :)  Even if it wasn't killing Tomcat, the
amount of cruft in WEB-INF/lib is ridiculous!

-- brian

---------------------------------------------------------------------
To start a new topic, e-mail: users@tomcat.apache.org
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Garbage Collection and Class unloading

Posted by David Smith <dn...@cornell.edu>.
Others with more experience in the garbage collection may chime in, but 
it's my impression that the garbage collection tends to have it's own 
mind.  You can try to force it, but that's no guarantee it will garbage 
collect anything.  I'd think your best bet is to clean out all the dead 
in-house code and then thin out the dependencies until it stops 
building.  If nothing else, refactor your code to pair down the multiple 
versions of libraries.

--David

Brian Munroe wrote:
> Can someone explain a little bit about classloading really quick?
>
> Let me preface this with: I am maintaining an application which I did
> not develop.
>
> Looking at the WEB-INF/lib directory, it has around 76 different jar
> files, some actually used in the application, some (well, most) not.
> They either pertain to legacy features or are functionality duplicate
> (two different versions of Oracle driver libraries, for example)
>
> I am trying to tune Tomcat because it keeps running out PermGen space,
> so I am using jconsole to inspect the JVM.  I suppose it isn't really
> a profiler, but it is a start.
>
> According to jconsole, after doing many application development cycles
> of remove->deployment of *.war to Tomcat (via manager), it looks like
> as many as 20k classes are loaded.  I was under the impression that
> the garbage collector would unload classes as necessary.
>
> I tried to force a GC via jconsole, it reduced the heap memory like it
> should, and it unloaded a few classes pertaining to reflection, but
> nothing like what I was hoping for.  I then leave it be for several
> hours, and all magic like, the GC unloads about 4k classes.
>
> First question.   Anyone tell me why it doesn't unload classes when I
> am trying to force it?  Is classloading/unloading not even the same as
> garbage collection?
>
> Second question.  Is having 20k classes loaded normal for a middle
> sized application?  I am assuming if I remove all the unnecessary jars
> from WEB-iNF/lib I can reduce that number?  Would it benefit anything
> to place them in shared/lib?
>
> Third:  If over 75% of the classes in the jars aren't being called
> anywhere in the application, even though they get loaded on the
> initial application deployment, shouldn't the GC unload them almost
> immediately, since there aren't any open resources using these
> classes.
>
> Fourth question:  Do my JAVA_OPTS looks decent?
>
> JAVA_OPTS="-Xms512m -Xmx512m -server
> -Dcom.sun.management.jmxremote
> -Dcom.sun.management.jmxremote.port=8114
> -Dcom.sun.management.jmxremote.ssl=false
> -Dcom.sun.management.jmxremote.authenticate=false
> -verbose:gc
> -XX:+PrintClassHistogram
> -XX:+PrintGCDetails
> -XX:MaxPermSize=128m"
>
> many thanks!
>
> -- brian
>
> ps.  My platform looks like:  Solaris 9 (SPARC), Tomcat 5.5.23, JDK
> 1.6.0_02 (32-bit)
>
> ---------------------------------------------------------------------
> To start a new topic, e-mail: users@tomcat.apache.org
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
>
>   


---------------------------------------------------------------------
To start a new topic, e-mail: users@tomcat.apache.org
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


RE: Garbage Collection and Class unloading

Posted by "Caldarale, Charles R" <Ch...@unisys.com>.
> From: Christopher Schultz [mailto:chris@christopherschultz.net] 
> Subject: Re: Garbage Collection and Class unloading
> 
> I thought a lot of the talk on this list about PermGen was that it was
> filling up and never being cleaned-up. Maybe that was just folks
> legitimately keeping lots of data around for a long time.

More likely to be accidentally than legitimately.  As long as there are
references to a Class object or instances of the class around, the Class
object can't be removed.

> Loading a class into memory from bytes doesn't interact with
> the GC any differently than loading an array of bytes from
> any other file.

Actually it does.  It is true that every class eventually becomes a byte
array, but that byte array is passed to ClassLoader.defineClass(), which
registers it with GC.  At the end of a full collection, the class
registration list is examined for unreachable classes, which are then
removed from the list and sent off for cleanup.  Such cleanup includes
getting rid of any JIT-processed methods in the code cache, among other
internal JVM structures.  On the next full GC, such java.lang.Class
instances are no longer in the registration list and are simply
discarded like any other unreachable object.

> ClassLoaders themselves don't have any magic in them.

That's true, except for the native code behind the
ClassLoader.defineClass() method (which is final, so can't be overridden
by subclasses); all of this java.lang.Class manipulation occurs under
the covers in the non-Java core of the JVM.

 - Chuck


THIS COMMUNICATION MAY CONTAIN CONFIDENTIAL AND/OR OTHERWISE PROPRIETARY
MATERIAL and is thus for use only by the intended recipient. If you
received this in error, please contact the sender and delete the e-mail
and its attachments from all computers.

---------------------------------------------------------------------
To start a new topic, e-mail: users@tomcat.apache.org
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Garbage Collection and Class unloading

Posted by Christopher Schultz <ch...@christopherschultz.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Chuck,

As always, thanks for correcting my misunderstandings of the JVM and GC.

Caldarale, Charles R wrote:

> All instances of java.lang.Class are allocated within the PermGen from
> the get-go; there is no migration into or out of PermGen.  (The tenured
> generation does operate as you describe.)

I didn't realize that. I guess the JVM figures that Class objects need
not actually earn their tenure, since they are likely to be loaded for a
long time. Nice optimization.

>> I'm a little hazy on PermGen, actually, but I think it 
>> /never/ gets cleaned up.
> 
> Not true, except if one esoteric, non-standard GC algorithm is selected
> for the HotSpot JVM.  PermGen is cleaned up whenever a full collection
> occurs.

I thought a lot of the talk on this list about PermGen was that it was
filling up and never being cleaned-up. Maybe that was just folks
legitimately keeping lots of data around for a long time.

>> Second, class loading and GC are mostly unrelated
> 
> Not true - they're intimately connected.

I disagree. Loading a class into memory from bytes doesn't interact with
the GC any differently than loading an array of bytes from any other
file. The only connection between them would be through the JIT, which
needs to know that it's okay to free compiled-code-memory when the Class
object becomes collectible. ClassLoaders themselves don't have any magic
in them.

- -chris
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.7 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFG4XU+9CaO5/Lv0PARAjbgAKCHwbLHH5NqkCWKoc8zZg4NbhYpfgCeJ7GN
2uMnvqYazd/OkDYQMqskqg8=
=3qek
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To start a new topic, e-mail: users@tomcat.apache.org
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


RE: Garbage Collection and Class unloading

Posted by "Caldarale, Charles R" <Ch...@unisys.com>.
> From: Christopher Schultz [mailto:chris@christopherschultz.net] 
> Subject: Re: Garbage Collection and Class unloading
> 
> This used to happen because Class objects were never 
> discarded by the JVM.

That's not true, at least not since JVM 1.2 came into use.  Class
objects are discarded once there are no more instances of that type,
there are no references to the Class objects themselves, and class
unloading has not been inhibited by command-line option.

> using static fields to store big object trees and pushing 
> application data into something managed by Tomcat (JNDI, a
> Valve, or something like that).

There have also been related issues with other oft-used non-Tomcat
libraries, such as loggers. Not sure if all of this undesired references
have been cleaned up.

> The ClassLoader keeps all the java.lang.Class objects
> it ever loaded

Actually, the references go the other way - every instance of
java.lang.Class retains a pointer to its ClassLoader, and the
ClassLoader won't be discarded until all of its loaded classes are gone.
(It's possible that Tomcat's WebappClassLoader keeps track of all
classes it loads - I haven't checked - but the standard ClassLoader
implementations that come with the JRE do not.)  Individual instances of
java.lang.Class can be discarded at any time, as long as the constraints
noted above are complied with.

> and those will eventually go into the PermGen space 
> due to their long lives.

All instances of java.lang.Class are allocated within the PermGen from
the get-go; there is no migration into or out of PermGen.  (The tenured
generation does operate as you describe.)

> I'm a little hazy on PermGen, actually, but I think it 
> /never/ gets cleaned up.

Not true, except if one esoteric, non-standard GC algorithm is selected
for the HotSpot JVM.  PermGen is cleaned up whenever a full collection
occurs.

> Second, class loading and GC are mostly unrelated

Not true - they're intimately connected.  Note that it takes two full
GCs to get rid of java.lang.Class instances after they become
unreachable.  The first discovers that they're no longer active and
queues the instances for some cleanup processing.  The instances
themselves are not discarded until the next full GC, after the cleanup
has happened.

> Yes. You might even want to do -verbose:class if you want 
> some light reading.

At least reading it won't keep you awake...

 - Chuck


THIS COMMUNICATION MAY CONTAIN CONFIDENTIAL AND/OR OTHERWISE PROPRIETARY
MATERIAL and is thus for use only by the intended recipient. If you
received this in error, please contact the sender and delete the e-mail
and its attachments from all computers.

---------------------------------------------------------------------
To start a new topic, e-mail: users@tomcat.apache.org
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Garbage Collection and Class unloading

Posted by Christopher Schultz <ch...@christopherschultz.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Brian,

Brian Munroe wrote:
> Looking at the WEB-INF/lib directory, it has around 76 different jar
> files, some actually used in the application, some (well, most) not.
> They either pertain to legacy features or are functionality duplicate
> (two different versions of Oracle driver libraries, for example)

Yipes!

> I am trying to tune Tomcat because it keeps running out PermGen space,
> so I am using jconsole to inspect the JVM.  I suppose it isn't really
> a profiler, but it is a start.

Just FYI... dropping JAR files isn't likely to reduce your PermGen
usage... classes only get loaded when they're needed. If your
application doesn't use those JARs, they are basically ignored (except
maybe for being scanned for contents for faster class loading). But, you
don't have to worry about all those useless classes actually getting loaded.

You should certainly get rid of useless libraries... just make sure
you're not doing it for the wrong reasons.

> According to jconsole, after doing many application development cycles
> of remove->deployment of *.war to Tomcat (via manager), it looks like
> as many as 20k classes are loaded.  I was under the impression that
> the garbage collector would unload classes as necessary.

This used to happen because Class objects were never discarded by the
JVM. Now, it usually happens when your application somehow stashes an
object somewhere that never goes away. There are several ways to do
that, but off the top of my head I can really only think of one or two:
using static fields to store big object trees and pushing application
data into something managed by Tomcat (JNDI, a Valve, or something like
that).

What ends up happening is that you put some object in one of these
places and, in order to stick around, the parent ClassLoader must remain
in memory (i.e. /not/ GC'd). The ClassLoader keeps all the
java.lang.Class objects it ever loaded, and those will eventually go
into the PermGen space due to their long lives.

I'm a little hazy on PermGen, actually, but I think it /never/ gets
cleaned up. That sounds kinda stupid, but I'm not smart enough to write
my own JVM so what the heck do I know, anyway? If PermGen never gets
cleaned up, maybe your Class objects are just making it into PermGen
naturally, and you are just suffering the consequences of many reloads.

Why are you reloading your webapp so many times? Is this just a
development environment, or do you do this in production?

> I tried to force a GC via jconsole, it reduced the heap memory like it
> should, and it unloaded a few classes pertaining to reflection, but
> nothing like what I was hoping for.  I then leave it be for several
> hours, and all magic like, the GC unloads about 4k classes.

Hmm... that torpedoes my "natural" theory above. Any idea what might
happen in those 4 hours?

> First question.   Anyone tell me why it doesn't unload classes when I
> am trying to force it?  Is classloading/unloading not even the same as
> garbage collection?

First, you can't force the JVM to do anything. Runtime.gc() basically
says to the garbage collector, "now would be a good time to do a
collection", but there's no guarantee. Second, class loading and GC are
mostly unrelated, although as you're seeing, things can get fuzzy when
you're observing problems in either or both areas.

> Second question.  Is having 20k classes loaded normal for a middle
> sized application?

It's not totally crazy, but it is a little high. There are something
like 6k classes that ship with the JVM alone. Of course, you're probably
not using AWT and Swing and stuff like that, but still, there are a lot
of classes out there. Also, Tomcat has a lot of its own classes, and
uses many classes from its dependent libraries, etc.

My relatively small application in development currently has 3386
classes loaded in what looks like 150 ClassLoaders (many of which show
as 'dead' using jmap), and it's been up for several hours at this point
under almost no load.

The same application (well, the last release) in production has 4046
classes loaded, and has been running since 12 July.

> I am assuming if I remove all the unnecessary jars
> from WEB-iNF/lib I can reduce that number?  Would it benefit anything
> to place them in shared/lib?

No! Keep your application and all it's dependencies together. As I
asserted above, reducing the JARs probably won't help.

> Third:  If over 75% of the classes in the jars aren't being called
> anywhere in the application, even though they get loaded on the
> initial application deployment, shouldn't the GC unload them almost
> immediately, since there aren't any open resources using these
> classes.

The classes should never get loaded in the first place.

> Fourth question:  Do my JAVA_OPTS looks decent?

Yes. You might even want to do -verbose:class if you want some light
reading.

Hope that helps,
- -chris
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.7 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFG4Lvo9CaO5/Lv0PARAkOpAKC6NAM4rH92WDNfpOyKkpnqHLKABQCeOGu0
Gkdkng6CaqDVrnar8LCrWmE=
=7fi9
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To start a new topic, e-mail: users@tomcat.apache.org
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org