PermGen 的标志未按预期工作:-XX:+CMSClassUnloadingEnabled 和 -XX:+CMSPermGenSweepingEnabled
Flags for PermGen not working as expected: -XX:+CMSClassUnloadingEnabled and -XX:+CMSPermGenSweepingEnabled
我有以下代码(有意地)生成 PermGen java.lang.OutOfMemoryError
:
public class Main {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, InterruptedException {
String name = "MyClass";
DynamicClassLoader cl = new DynamicClassLoader();
int i = 0;
while (true) {
//code for generating the binary for a class to be loaded.
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
cw.visit(Opcodes.V1_7, Opcodes.ACC_PUBLIC, name + ++i, null, "java/lang/Object", null);
MethodVisitor con = cw.visitMethod(Opcodes.ACC_PUBLIC, "", "()V", null, null);
con.visitCode();
con.visitVarInsn(Opcodes.ALOAD, 0);
con.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "", "()V", false);
con.visitInsn(Opcodes.RETURN);
con.visitMaxs(1, 1);
cw.visitEnd();
//binary code for class successfully generated
Class clazz = cl.defineClass(name + i, cw.toByteArray());
Object o = clazz.newInstance();
System.out.println(o.getClass().getName());
}
}
private static class DynamicClassLoader extends ClassLoader {
public Class defineClass(String name, byte[] b) {
return defineClass(name, b, 0, b.length);
}
}
}
I 运行 Java 7 中的此代码。正如预期的那样,它得到 java.lang.OutOfMemoryError: PermGen space
错误。
当我尝试 运行 这个程序与提到的标志如下:
java -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled -jar target/permgen.jar
,我仍然得到同样的错误,在与我 运行 没有标志时完全相同的点。
我预计,如果我放置这些标志,即使不会完全刷新 PermGen,至少也会看到部分改进。但事实并非如此。
问题:我是不是误解了那些标志的意思?如果是这种情况,您能详细说明一下吗?否则,有什么建议吗?
N.B。 java -version
的输出是:
java version "1.7.0_95"
OpenJDK Runtime Environment (IcedTea 2.6.4) (7u95-2.6.4-3)
OpenJDK 64-Bit Server VM (build 24.95-b01, mixed mode)
所有类加载器都保留对其加载的所有 类 的强引用。在您的示例中,您一直重复使用 DynamicClassLoader
的单个实例。该类加载器依次保留对您加载的所有 类 的强引用。所以垃圾收集器永远不会看到它可以收集的未引用对象。
如果您修改测试用例以使用单独的类加载器,垃圾收集器应该能够识别出您的 类 未被使用并且应该回收内存。
我有以下代码(有意地)生成 PermGen java.lang.OutOfMemoryError
:
public class Main {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, InterruptedException {
String name = "MyClass";
DynamicClassLoader cl = new DynamicClassLoader();
int i = 0;
while (true) {
//code for generating the binary for a class to be loaded.
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
cw.visit(Opcodes.V1_7, Opcodes.ACC_PUBLIC, name + ++i, null, "java/lang/Object", null);
MethodVisitor con = cw.visitMethod(Opcodes.ACC_PUBLIC, "", "()V", null, null);
con.visitCode();
con.visitVarInsn(Opcodes.ALOAD, 0);
con.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "", "()V", false);
con.visitInsn(Opcodes.RETURN);
con.visitMaxs(1, 1);
cw.visitEnd();
//binary code for class successfully generated
Class clazz = cl.defineClass(name + i, cw.toByteArray());
Object o = clazz.newInstance();
System.out.println(o.getClass().getName());
}
}
private static class DynamicClassLoader extends ClassLoader {
public Class defineClass(String name, byte[] b) {
return defineClass(name, b, 0, b.length);
}
}
}
I 运行 Java 7 中的此代码。正如预期的那样,它得到 java.lang.OutOfMemoryError: PermGen space
错误。
当我尝试 运行 这个程序与提到的标志如下:
java -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled -jar target/permgen.jar
,我仍然得到同样的错误,在与我 运行 没有标志时完全相同的点。 我预计,如果我放置这些标志,即使不会完全刷新 PermGen,至少也会看到部分改进。但事实并非如此。
问题:我是不是误解了那些标志的意思?如果是这种情况,您能详细说明一下吗?否则,有什么建议吗?
N.B。 java -version
的输出是:
java version "1.7.0_95"
OpenJDK Runtime Environment (IcedTea 2.6.4) (7u95-2.6.4-3)
OpenJDK 64-Bit Server VM (build 24.95-b01, mixed mode)
所有类加载器都保留对其加载的所有 类 的强引用。在您的示例中,您一直重复使用 DynamicClassLoader
的单个实例。该类加载器依次保留对您加载的所有 类 的强引用。所以垃圾收集器永远不会看到它可以收集的未引用对象。
如果您修改测试用例以使用单独的类加载器,垃圾收集器应该能够识别出您的 类 未被使用并且应该回收内存。