Class.forName cause ClassLoader objects moved to tenured generation

Krystal Mok rednaxelafx at gmail.com
Sun Feb 26 21:29:42 PST 2012


Hi Liquan,

That's because Class.forName() will keep a reference to your class loader
in the SystemDictionary (for being an initiating loader of the class, in
your example "java.lang.String"), whereas ClassLoader.loadClass() won't.

SystemDictionary is the place where HotSpot VM keeps track of all currently
loaded classes, with the mapping of:
(class name, class loader) => class
The "class loader" part includes both defining class loaders and initiating
class loaders.

During minor GC:
The whole SystemDictionary is a part of the root set in a minor GC. Class
unloading doesn't happen. The class loaders referenced by the
SystemDictionary aren't collected, either.
So in you example, the loader are all kept alive with Class.forName().

[GC [DefNew: 576K->64K(576K), 0.0025942 secs][Tenured: 1634K->166K(1664K),
0.0169541 secs] 1871K->166K(2240K), 0.0197106 secs]

This kind of GC log shows that a collection started out as a minor GC, but
failed to allocate enough space in the old generation to promotion
surviving objects, so it bailed out and fell back to a full GC which
collects the whole GC heap. This kind of fallback doesn't print "[Full GC"
in the GC logs, so it's kind of tricky to tell if you don't know the gory
details.
You could turn on -XX:+PrintPromotionFailure to see promotion failure in
action.

A full GC will collect dead class loaders and unload unused classes. So
your example won't get an OOME just for filling up the old generation with
class loaders.

Just to be clear: this behavior wouldn't be considered a bug in the VM.
You'll have to take care of class loading more carefully in your
application.

HTH,
- Kris

2012/2/27 ºÆÃ÷ <liquan.liu at alipay.com>

> Hi all,
>
> I have seen Class.forName() causes the tenured generation got filled with
> custom ClassLoader objects. I suspect something JVM done internally will
> move the ClassLoader objects to tenured generation. For example, the
> following code:
> ========================
> public class Test  {
>   public static void main(String[] args) throws Exception {
>     for (int i=0 ;i<30000;i++) {
>         test();
>     }
>   }
>   private static void test() throws Exception {
>     MyClassLoader mcl = new MyClassLoader();
>     Class.forName("java.lang.String", false, mcl);
>   }
> }
>
> public class MyClassLoader extends ClassLoader {}
> =========================
> will output gc log:
>
> [GC [DefNew: 512K->64K(576K), 0.0041095 secs] 512K->344K(1984K), 0.0042064
> secs]
> [GC [DefNew: 576K->64K(576K), 0.0032096 secs] 856K->682K(1984K), 0.0032937
> secs]
> [GC [DefNew: 575K->63K(576K), 0.0032085 secs] 1194K->1021K(1984K),
> 0.0033686 secs]
> [GC [DefNew: 575K->64K(576K), 0.0025146 secs] 1533K->1359K(1984K),
> 0.0026305 secs]
> [GC [DefNew: 576K->64K(576K), 0.0025942 secs][Tenured: 1634K->166K(1664K),
> 0.0169541 secs] 1871K->166K(2240K), 0.0197106 secs]
> [GC [DefNew: 512K->64K(576K), 0.0019209 secs] 678K->505K(1984K), 0.0020053
> secs]
> [GC [DefNew: 576K->63K(576K), 0.0022846 secs] 1017K->844K(1984K),
> 0.0024271 secs]
> [GC [DefNew: 575K->63K(576K), 0.0023358 secs] 1356K->1182K(1984K),
> 0.0024235 secs]
> [GC [DefNew: 575K->64K(576K), 0.0025660 secs][Tenured: 1457K->166K(1536K),
> 0.0136841 secs] 1694K->166K(2112K), 0.0164004 secs]
>
>
> If change the Class.forName to loadClass:
> ========================
> private static void test() throws Exception {
>    MyClassLoader mcl = new MyClassLoader();
>    mcl.loadClass("java.lang.String");
> }
> ========================
> then gc log will be:
>
> [GC [DefNew: 512K->63K(576K), 0.0028769 secs] 512K->138K(1984K), 0.0029627
> secs]
> [GC [DefNew: 575K->0K(576K), 0.0009856 secs] 650K->138K(1984K), 0.0010711
> secs]
> [GC [DefNew: 512K->0K(576K), 0.0006255 secs] 650K->138K(1984K), 0.0007062
> secs]
> [GC [DefNew: 512K->0K(576K), 0.0002065 secs] 650K->138K(1984K), 0.0002861
> secs]
> [GC [DefNew: 512K->0K(576K), 0.0001936 secs] 650K->138K(1984K), 0.0002674
> secs]
> [GC [DefNew: 512K->0K(576K), 0.0002045 secs] 650K->138K(1984K), 0.0002796
> secs]
> [GC [DefNew: 512K->0K(576K), 0.0001704 secs] 650K->138K(1984K), 0.0002481
> secs]
> [GC [DefNew: 512K->0K(576K), 0.0002229 secs] 650K->138K(1984K), 0.0003118
> secs]
>
> Reproduced in both jdk1.5 and 1.6.
>
> Can someone enlight me what's happening inside jvm (regarding class load
> and gc) ?
>
> Thanks.
>
> ________________________________
>
> This email (including any attachments) is confidential and may be legally
> privileged. If you received this email in error, please delete it
> immediately and do not copy it or use it for any purpose or disclose its
> contents to any other person. Thank you.
>
>
> ±¾µçÓÊ(°üÀ¨Èκθ½¼þ)¿ÉÄܺ¬ÓлúÃÜ×ÊÁϲ¢ÊÜ·¨Âɱ£»¤¡£ÈçÄú²»ÊÇÕýÈ·µÄÊÕ¼þÈË£¬ÇëÄúÁ¢¼´É¾³ý±¾Óʼþ¡£Çë²»Òª½«±¾µçÓʽøÐи´ÖƲ¢ÓÃ×÷ÈκÎÆäËûÓÃ;¡¢»ò͸¶±¾ÓʼþÖ®ÄÚÈÝ¡£Ð»Ð»¡£
>
> _______________________________________________
> hotspot-gc-use mailing list
> hotspot-gc-use at openjdk.java.net
> http://mail.openjdk.java.net/mailman/listinfo/hotspot-gc-use
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/hotspot-gc-use/attachments/20120227/c3ab8844/attachment.html 


More information about the hotspot-gc-use mailing list