我曾看到 Class.forName() 导致了老年代被填满。我怀疑JVM内部有些东西会将ClassLoader对象转移到老年代。例如,以下代码:
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 cl = new MyClassLoader();
Class.forName("java.lang.String", false, cl);
}
}
public class MyClassLoader extends ClassLoader {}
将输出gc日志:
[GC [DefNew: 512K->64K(576K), 0.0041095秒] 512K->344K(1984K), 0.0042064秒]
[GC [DefNew: 576K->64K(576K), 0.0032096秒] 856K->682K(1984K), 0.0032937秒]
[GC [DefNew: 575K->63K(576K), 0.0032085秒] 1194K->1021K(1984K), 0.0033686秒]
[GC [DefNew: 575K->64K(576K), 0.0025146秒] 1533K->1359K(1984K), 0.0026305秒]
[GC [DefNew: 576K->64K(576K), 0.0025942秒][Tenured: 1634K->166K(1664K), 0.0169541秒] 1871K->166K(2240K), 0.0197106秒]
[GC [DefNew: 512K->64K(576K), 0.0019209秒] 678K->505K(1984K), 0.0020053秒]
[GC [DefNew: 576K->63K(576K), 0.0022846秒] 1017K->844K(1984K), 0.0024271秒]
[GC [DefNew: 575K->63K(576K), 0.0023358秒] 1356K->1182K(1984K), 0.0024235秒]
[GC [DefNew: 575K->64K(576K), 0.0025660秒][Tenured: 1457K->166K(1536K), 0.0136841秒] 1694K->166K(2112K), 0.0164004秒]
如果将Class.forName更改为loadClass:
private static void test() throws Exception {
MyClassLoader cl = new MyClassLoader();
cl.loadClass("java.lang.String");
//Class.forName("java.lang.String", false, cl);
}
然后gc的输出将会是:
[GC [DefNew: 512K->63K(576K), 0.0028769秒] 512K->138K(1984K), 0.0029627秒]
[GC [DefNew: 575K->0K(576K), 0.0009856秒] 650K->138K(1984K), 0.0010711秒]
[GC [DefNew: 512K->0K(576K), 0.0006255秒] 650K->138K(1984K), 0.0007062秒]
[GC [DefNew: 512K->0K(576K), 0.0002065秒] 650K->138K(1984K), 0.0002861秒]
[GC [DefNew: 512K->0K(576K), 0.0001936秒] 650K->138K(1984K), 0.0002674秒]
[GC [DefNew: 512K->0K(576K), 0.0002045秒] 650K->138K(1984K), 0.0002796秒]
[GC [DefNew: 512K->0K(576K), 0.0001704秒] 650K->138K(1984K), 0.0002481秒]
[GC [DefNew: 512K->0K(576K), 0.0002229秒] 650K->138K(1984K), 0.0003118秒]
在sun jdk1.5和1.6中复现。JVM内部(类加载和垃圾回收)到底发生了什么?
谢谢。