Permanent Generation and garbage collection

T

Tassilo Horn

Hi all,

we have some MDA-style library here. Basically, you define some schema
(something like a UML class diagram), and then a code generator creates
bytecode for the classes and associations in memory, and a custom class
loader invokes ClassLoader.defineClass(). Then you can create graphs
(like UML object diagrams) conforming that schema, which instantiates
the generated classes.

Now there's also a model-transformation language, that creates new
graphs conforming to new schemas out of old graphs, and those new
classes are also compiled in memory. Many transformations run in
several steps, and each step compiles new classes.

So it's not seldom, that finally there are 10.000 classes in memory,
which results in an OutOfMemoryError: PermGen space. Increasing PermGen
space using the relevant command line switch works, but isn't there a
better way?

For example in such step-by-step transformations, I'm sure that the
classes created in intermediate steps cannot be used from outside, and
that it's ok to forget the classes defined in step i when finishing step
i+1. For those intermediate classes, I do know the exact prefix of the
fully qualified name all those classes share, so I'm looking for
something like

System.forgetAllClasses(myPrefix);

Any pointers are highly appreciated.

Bye,
Tassilo
 
T

Tassilo Horn

Hi Thomas,
As far as I know, the JVM may "forget" a class only by forgetting the
ClassLoader instance which loaded the class, which happens only if
nobody references the ClassLoader,

Our ClassLoader is a singleton, so it references itself. ;-)
any of its loaded classes, any of the instances created using such
classes, or any of the static fields declared in said classes.

Well, I think that's the case.
So if you want to load 10000 classes in a single ClassLoader, then you
will have to size PermGen such that all 10000 classes fit
simultaneously.

If you want to forget some classes, then you will have to create
distinct ClassLoader instances. Maybe each of your defined classes
could use a specific ClassLoader ?

If you are right, a distinct ClassLoader for each schema would make much
sense.

Thanks for the pointers,
Tassilo
 
T

Tassilo Horn

Hi again,
If you are right, a distinct ClassLoader for each schema would make
much sense.

Ok, now I've done that. Our ClassLoader is now a "multi-singleton",
where the instances are held in a Map from schemaName to ClassLoader.
Whenever I don't need a schema anymore, I release its ClassLoader and
call System.gc(). I track the number of ClassLoaders, and it's at most
3, which is correct.

Unfortunately, I still get the OutOfMemoryError: PermGen, although if
the classes were really freed from the permanent generation, I should
need about half the space I needed before that change.

Is there some way to check, if someone still references the ClassLoader
or any Object of a class loaded by that ClassLoader?

Bye,
Tassilo
 
L

Lew

Tassilo said:
call System.gc().

Generally useless, especially so with respect to the permanent generation.

But going back to your question:
Increasing PermGen space using the relevant command line switch works,
but isn't there a better way?

What constitutes "better"? You know you need a lot of perm-gen space, you
allocate it. That seems the epitome of goodness.

-XX:+CMSClassUnloadingEnabled perhaps?

The relevant command-line switches aren't mutually exclusive. You could use
them in combination.
 
T

Tassilo Horn

Hi Lew,
Generally useless, especially so with respect to the permanent
generation.
Noted.

But going back to your question:

What constitutes "better"?

No command line switches -- the system arranges all for a user.
You know you need a lot of perm-gen space, you allocate it. That
seems the epitome of goodness.

Well, but I don't too much perm-gen space at a given point in time. I
only need a lot if I cannot free it by garbage collecting classes I
don't use anymore.
-XX:+CMSClassUnloadingEnabled perhaps?

No, it doesn't seem to make a (noticable) difference.
The relevant command-line switches aren't mutually exclusive. You
could use them in combination.

Yes, done that. No matter if I add -XX:+CMSClassUnloadingEnabled, I
have to set max perm-gen to the same amount. (Ok, maybe I could drop a
few MBs, but it's not that much that it makes a difference.)

Do you know if Thomas was right with his assumption that if a
ClassLoader has no references anymore, as well as all classes it loaded,
then it should be garbage collected?

Bye,
Tassilo
 
R

Roedy Green

Is there some way to check, if someone still references the ClassLoader
or any Object of a class loaded by that ClassLoader?

see http://mindprod.com/jgloss/profiler.html
for tools that might help you figure out what is pinning your classes
in RAM.
--
Roedy Green Canadian Mind Products
http://mindprod.com

"You can have quality software, or you can have pointer arithmetic; but you cannot have both at the same time."
~ Bertrand Meyer (born: 1950 age: 59) 1989, creator of design by contract and the Eiffel language.
 
T

Tassilo Horn

Hi Patricia,
...

The JLS certainly permits garbage collection in that situation. See
http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.7
That does not guarantee it will happen.
Thanks.

I wonder whether it would be possible to use
java.lang.ref.WeakReference and a ReferenceQueue to see whether any of
the ClassLoader and Class objects are being freed?

For the custom ClassLoader I do count object creations and finalizations
now. And indeed, after I dropped the last reference to some class
loader (at least in my code, dunno if there are references to it in the
JVM internals), the finalize() method isn't called. So I guess, there
are still references to the classes it loaded, or to objects of those
classes.

So I'll play around with the profilers Roedy links.

Bye,
Tassilo
 
L

Lew

Tassilo said:
For the custom ClassLoader I do count object creations and finalizations
now. And indeed, after I dropped the last reference to some class
loader (at least in my code, dunno if there are references to it in the
JVM internals), the finalize() method isn't called. So I guess, there
are still references to the classes it loaded, or to objects of those
classes.

Finalizers make life worse for GC. Patricia's suggestions will allow you to
monitor that things are released without the overhead of finalize().

For one thing, having a non-trivial finalize() guarantees that a dead object
will need a minimum of two collection cycles to release. If you are using
lots of heap with finalizable objects, the collector might not be able to gain
enough in one collection to avoid OOME.
 
T

Tassilo Horn

Hi Lew,
Finalizers make life worse for GC. Patricia's suggestions will allow
you to monitor that things are released without the overhead of
finalize().

Ok, I'll have a look at that.
For one thing, having a non-trivial finalize() guarantees that a dead
object will need a minimum of two collection cycles to release.

Is that non-trivial and will hinder GC?

@Override
protected void finalize() throws Throwable {
synchronized (this) {
instanceCount--;
}
super.finalize();
}
If you are using lots of heap with finalizable objects, the collector
might not be able to gain enough in one collection to avoid OOME.

Only my custom ClassLoader overrides finalize(), and those are only 4
instances at the time I get the OOME with 128MB PermGen space. Each of
them loads about 2000 classes.

Bye,
Tassilo
 
J

Joshua Cranmer

Tassilo said:
For the custom ClassLoader I do count object creations and finalizations
now. And indeed, after I dropped the last reference to some class
loader (at least in my code, dunno if there are references to it in the
JVM internals), the finalize() method isn't called. So I guess, there
are still references to the classes it loaded, or to objects of those
classes.

Using finalize() can wreak havoc with garbage collection: at they very
least, it requires two collection attempts to actually clear the memory.
I have to imagine that for the purposes of unloading storage space for
classes, it will require many more, probably more than the garbage
collector will care to attempt in memory pressure situations.

If you play around with java.lang.ref, you can avoid some potential
finalize() problems, although I don't know how well reference queues
work in this regard.
 
D

Daniel Pitts

Tassilo said:
Hi again,


Ok, now I've done that. Our ClassLoader is now a "multi-singleton",
where the instances are held in a Map from schemaName to ClassLoader.
Whenever I don't need a schema anymore, I release its ClassLoader and
call System.gc(). I track the number of ClassLoaders, and it's at most
3, which is correct.

Unfortunately, I still get the OutOfMemoryError: PermGen, although if
the classes were really freed from the permanent generation, I should
need about half the space I needed before that change.

Is there some way to check, if someone still references the ClassLoader
or any Object of a class loaded by that ClassLoader?

Bye,
Tassilo
You can inspect memory using most popular profilers. I prefer JProfiler.
It is a commercial app, but they have a trial period. JProbe is
another option, and netbeans comes with a free one. I haven't used any
of them to track memory issues, but I believe they are all similar in
that regard.


You might als try using -XX:MaxPermSize=256m and see if that fixes your
problem.
 
T

Tassilo Horn

Hi Thomas,
Is that non-trivial and will hinder GC?

[garbage collection & finalization]

Thanks a ton for this excellent explanation!
More to the point of the discussion, it is plausible that the GC needs
to handle classes and class loaders "specially", and it is conceivable
that adding a non-empty ClassLoader.finalize() may significantly alter
the way the JVM may unload classes.

Well, this was only a quick test to check if any ClassLoader is
collected. And I guessed, that when PermGen space runs out, the JVM
will try harder to collect unused classes and free them. Commenting out
the finalize() doesn't seem to make a difference, so I guess that still
classes that ClassLoader referenced are in use.

I'm going to do some profiling as the others here suggested.

Again, thanks a lot for explaining those details!
Tassilo
 
T

Tassilo Horn

Hi Daniel,
You can inspect memory using most popular profilers. I prefer
JProfiler. It is a commercial app, but they have a trial period.
JProbe is another option, and netbeans comes with a free one.

I'll try those.
I haven't used any of them to track memory issues, but I believe they
are all similar in that regard.
Ok.

You might als try using -XX:MaxPermSize=256m and see if that fixes your
problem.

It does, but IMO it's the wrong approach. When doing overly complex
model transformations there's no bound on the number of generated
classes, and eventually increasing PermGen won't be an option anymore.
Ok, that's a not too realistic worst-case scenario, but when I can tell
that some classes won't be needed anymore, then it's the right thing to
release them. If there are still references which prevent that, I
consider that a bug in our implementation, so it seems worthwhile to
spend some time debugging that.

Thanks for the pointers!

Bye,
Tassilo
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,740
Latest member
JudsonFrie

Latest Threads

Top