【问题标题】:Flags for PermGen not working as expected: -XX:+CMSClassUnloadingEnabled and -XX:+CMSPermGenSweepingEnabledPermGen 的标志未按预期工作:-XX:+CMSClassUnloadingEnabled 和 -XX:+CMSPermGenSweepingEnabled
【发布时间】:2016-12-16 12:05:58
【问题描述】:

我有以下代码(有意)生成 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);
        }
    }
}

我在 Java 7 中运行此代码。正如预期的那样,它得到 java.lang.OutOfMemoryError: PermGen space 错误。 当我尝试使用上述标志运行该程序时,如下所示:

java -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled -jar target/permgen.jar

,我仍然得到相同的错误,与我在没有标志的情况下运行它时完全相同。 我希望如果我设置这些标志,如果不是 PermGen 的完全刷新,至少会看到部分改进。但事实并非如此。

问题:我是否误解了这些标志的含义?如果是这种情况,您能详细说明一下吗?否则,有什么建议吗?

注意java -version 的输出是:

java 版本“1.7.0_95”

OpenJDK 运行时环境 (IcedTea 2.6.4) (7u95-2.6.4-3)

OpenJDK 64 位服务器 VM(内部版本 24.95-b01,混合模式)

【问题讨论】:

  • 您能否修改您的测试用例,使您的DynamicClassLoader 实例不会在整个测试期间保留? AFAIK,所有类加载器都保留对它们加载的所有类的引用。除非你的类加载器被 GC'ed,否则你的类不能被 GC'ed。
  • @omajid 谢谢。你一针见血。 :)。请将其作为回复发布以接受它。

标签: java out-of-memory java-7 openjdk permgen


【解决方案1】:

所有类加载器都会对它们加载的所有类保持强引用。在您的示例中,您继续重用DynamicClassLoader 的单个实例。这个类加载器反过来保持对您加载的所有类的强引用。所以垃圾收集器永远不会看到它可以收集的未引用对象。

如果您修改测试用例以使用单独的类加载器,垃圾收集器应该能够识别出您的类没有被使用并应该回收内存。

【讨论】:

    猜你喜欢
    • 2011-04-12
    • 1970-01-01
    • 1970-01-01
    • 2018-08-15
    • 2016-02-23
    • 2015-06-06
    • 2021-11-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多