tags:

views:

2583

answers:

6

I recently began profiling an osgi java application that I am writing using VisualVM. One thing I have noticed is that when the application starts sending data to a client (over JMS), the number of loaded classes starts increasing at a steady rate. The Heap size and the PermGen size remains constant, however. The number of classes never falls, even after it stops sending data. Is this a memory leak? I think it is, because the loaded classes have to be stored somewhere, however the heap and permgen never increase even after I run the application for several hours.

For the screenshot of my profiling application go here

A: 

Yes, it's usually a memory leak (since we don't really deal with memory directly, it's more of a class instance leak). I've gone through this process before and usually it's some listener added to an old toolkit that didn't remove it self.

In older code, A listener relationship causes the "listener" object to remain around. I'd look at older toolkits or ones that haven't been through many revs. Any long-existing library running on a later JDK would know about reference objects which removes the requirement for "Remove Listener".

Also, call dispose on your windows if you recreate them each time. I don't think they ever go away if you don't (Actually there is also a dispose on close setting).

Don't worry about Swing or JDK listeners, they should all use references so you should be okay.

Bill K
+3  A: 

Unless I misunderstand, we're looking here at loaded classes, not instances.

When your code first references a class, the JVM has the ClassLoader go out and fetch the information about the class from a .class file or the like.

I'm not sure under what conditions it would unload a class. Certainly it should never unload any class with static information.

So I would expect a pattern roughly like yours, where as your application runs it goes into areas and references new classes, so the number of loaded classes would go up and up.

However, two things seems strange to me:

  1. Why is it so linear?
  2. Why doesn't it plateau?

I would expect it to trend upwards, but in a wobbly line, and then taper off on the increase as the JVM has already loaded most of the classes your program references. I mean, there are a finite number of classes referenced in most applications.

Are you dynamically creating new classes on the fly somehow?

I would suggest running a simpler test app through the same debugger to get a baseline case. Then you could consider implementing your own ClassLoader that spits out some debug information, or maybe there is a tool to make it report.

You need to figure out what these classes being loaded are.

rice
+2  A: 

You might find some hotspot flags to be of use in understanding this behavior. This is a good reference:

http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp

And flags like:

  • -XX:-TraceClassLoading
  • -XX:-TraceClassUnloading
Alex Miller
+3  A: 

Are you dynamically creating new classes on the fly somehow?

Thanks for your help. I figured out what the problem is. In one of my classes, I was using Jaxb to create an XML string. In doing this, JAXB ueses reflection to create a new class.

JAXBContext context = JAXBContext.newInstance(this.getClass());

So although the JAXBContext wasn't saying around in the heap, the classes had been loaded.

I have run my program again, and I see a normal plateau as I would expect.

Kyle
+1  A: 

I'm willing to bet that your problem is related to bytecode generation.

Many libraries use CGLib, BCEL, Javasist or Janino to generate bytecode for new classes at runtime and then load them from controlled classloader. The only way to release these classes is to release all references to the classloader.

Since the classloader is held by each class, this also means that you should not release the references to all classes as well [1]. You can catch these with a decent profiler (I use Yourkit - search for multiple classloader instances with the same retained size)

One catch is that the JVM does not unload classes by default (the reason is backwards compatibility - that people assume (wrongly) that static initializers would be executed only once. The truth is that they get executed every time a class is loaded.) To enable unloading, you should pass some use the following options:

-XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled

(tested with JDK 1.5)

Even then, excessive bytecode generation is not a good idea, so I suggest you look in your code to find the culprit and cache the generated classes. Frequent offenders are scripting languages, dynamic proxies (including the ones generated by application servers) or huge Hibernate model (in this case you can just increase your permgen).

See also:

  1. http://blogs.sun.com/watt/resource/jvm-options-list.html
  2. http://blogs.sun.com/jonthecollector/entry/presenting_the_permanent_generation
  3. http://forums.sun.com/thread.jspa?messageID=2833028
ddimitrov
Even the JVM will generate classes for java.lang.reflect.Proxy and warmed up Field.get/set, Method.invoke and Constructor.newInstance (IIRC).
Tom Hawtin - tackline
Yes, you are right, still these generated classes are cached in the reflection layer, so should not be a reason for permgen leaks.
ddimitrov
A: 

Use the Eclipse Memory Analyzer to check for duplicated classes and memory leaks. It might happen that the same class gets loaded more than once.

Regards, Markus

kohlerm