12

I would like to know if the JVM normally unloads classes in order to decrease the PermGen space. So here my questions:

  1. Do Java classes ever get unloaded by default from a JVM?
  2. Does closing a Jar classloader unloads all the loaded classes from that jar?
  3. What commands/ways should be used to allow the unloading of classes?

FYI, I did try some of the solutions on the web but none of them answered my questions. (for example: What does JVM flag CMSClassUnloadingEnabled actually do?)

PS: I am referring to Java 6 + hibernate (The class loading is handled by hibernate)

Community
  • 1
  • 1
Adel Boutros
  • 10,205
  • 7
  • 55
  • 89
  • What kind of application do you have? – Thilo Jul 15 '13 at 10:45
  • It varies with JVM version and settings. To unload a class you must, at a minimum, remove all references to the class's class loader, and, obviously remove all references to the class itself and any instances of the class, including any references due to stacked call frames. More subtly, you must remove references to any classes that reference the removed class. (This means that you cannot remove a class which you reference in your "mainline" code using, eg, `new SomeClass` -- you must load the class starting with its name as a String.) – Hot Licks Jul 15 '13 at 10:53
  • @Thilo My application consist of dynamically loading classes provided by a jar. This jar can be changed "at runtime" by the user and after some jar changes, the application reaches a `OutOfMemoryError: PermGen space` because the old classes (from the disregarded jar) are never unloaded. – Adel Boutros Jul 15 '13 at 11:49

4 Answers4

3

The only way to get rid of loaded classes is to allow JVM to GC the class loader which loaded these classes by eliminating all references to this class loader. This is what happens in web servers when we undeploy a webapp.

Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275
  • But the problem in Java 6 is that URLClassLoader never really de-reference a Jar and thus the classes will never be unloaded, no? – Adel Boutros Jul 15 '13 at 11:47
  • Check my PS in the question – Adel Boutros Jul 15 '13 at 11:50
  • How do you change the jar at runtime? You have to get rid of the old classloader and all its classes before they can be unloaded. – Thilo Jul 15 '13 at 11:53
  • @AdelBoutros It is ok for URLClassLoader to still refer to the classes. If the only references to the classes are from their class loader and there are no references to the class loader, this forms an "island", which the garbage collector can handle just fine. – Brandon Jul 15 '13 at 12:25
  • @Thilo From what I know, hibernate handles the classloading internally – Adel Boutros Jul 15 '13 at 13:16
  • so this means that probably hibernate is not de-referencing the classes, right? – Adel Boutros Jul 15 '13 at 13:17
3

Currently the permanent generation is being collected by default.

The Permanent Generation is comprised of a single space, but does not have its own collector. Instead, this space is collected as part of the Old Generation.

According to this visualgc page.

In old JVMs you could enable this with the -XX:+CMSPermGenSweepingEnabled flag.

AFAIK classes get unloaded when they are not referenced from any ClassLoader.

java.lang.OutOfMemoryError: PermGen space errors are cause by memory leaks in class loaders. A common problem when undeploying/redeploying web applications.

MarcelK
  • 283
  • 2
  • 4
  • 11
2

Going to assume you're talking about HotSpot, the Oracle/Sun JVM.

  1. If there are no references to them. Note that all classes have a reference to their classloader and vice-versa, and all objects have a reference to their class.
  2. Maybe. What do you mean by "close"?
  3. Start the JVM with the options -XX:+UseConcMarkSweepGC and -XX:+CMSClassUnloadingEnabled. This will allow unloading of unused classes even if their classloader still exists.

See also Unloading classes in java?

Community
  • 1
  • 1
OrangeDog
  • 36,653
  • 12
  • 122
  • 207
  • Thank you for your answer. In my case, I have to dynamically attach a Jar to load new classes. Over time, I am getting `OutOfMemoryError: PermGen space` and I was wondering why doesn't the classes coming from the old jar get unloaded once the jar is disregarded. – Adel Boutros Jul 15 '13 at 11:46
2

Hibernate loads all the Entity classes in memory when the SessionFactory starts. On the other hand the Entity istances are loaded by Hibernate in a lazy way, only when needed.

Classes can be unloaded by the GC when the JVM needs memory. Entity istances are garbage collected too but, as any other object, only when there are no more references pointing at them. In other words Entity istances cannot be unloaded if the Hibernate session is still open. To unload them you need to clear the persistence context or close the session.

Atropo
  • 12,231
  • 6
  • 49
  • 62