我见过 Class.forName()导致终身一代被填满。我怀疑JVM内部会将ClassLoader对象移动到tenured generation。例如,以下代码:
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 log:
[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秒] [终身: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秒] [终身: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(class load和gc)里面发生了什么?
感谢。
答案 0 :(得分:1)
您的样本太少,无法真正显示GC行为差异的明确原因。首先,您的MyClassLoader
实际上不应该加载java.lang.String
类,因为它已经存在于引导类加载器中。你的ClassLoader对象(以及Class对象本身)应该一直移动到PermGen空间,所以你对它们在终身代中的猜测有点可疑。
基本上,你的问题“这里JVM内部发生了什么”过于笼统 - 只是读取GC日志输出并没有真正告诉你太多,因为即使看似微不足道的代码差异也可能导致GC模式大不相同,尤其是小测试代码。