java.lang.OutOfMemoryError: PermGen space: java reflection



我在代码中这样使用java反射:

Method method = LogFactory.class.getDeclaredMethod("getContextClassLoader");
method.setAccessible(true);
ClassLoader classLoader = (ClassLoader)method.invoke(null);
LogFactory.release(classLoader);

我用jprofiler可以看到很多这样的类sun.reflect.GeneratedMethodAccessor11

这些类每次调用都会增加

sun.reflect.BootstrapConstructorAccessorImpl
sun.reflect.NativeConstructorAccessorImpl
sun.reflect.DelegatingConstructorAccessorImpl
sun.reflect.DelegatingClassLoader

我想这就是为什么PermGen空间增加,如何清理这些类?

有一篇很好的文章讨论了在反射委托类加载器中潜在的本机内存使用。

当使用Java反射时,JVM有两种方法来访问反映的类的信息。它可以使用JNI访问器,或Java字节码访问器。如果它使用Java字节码访问器,则它需要有自己的Java类和类加载器(sun/reflect/GeneratedMethodAccessor类和太阳/反映/DelegatingClassLoader)。这些类和类加载器使用本机内存。访问器字节码也可以被JIT编译,这将进一步增加本机内存的使用。如果Java反射经常被使用,这可能会增加一个相当大的量本机内存使用。然后,JVM将首先使用JNI访问器对同一个类进行一定次数的访问后,将改为使用Java字节码访问器。这称为膨胀,当JVM从JNI访问器更改为字节码访问器。幸运的是,我们可以用一个Java属性来控制它。的属性告诉JVM有多少使用JNI访问器的次数。如果设置为0,则JNI总是使用访问器。因为字节码访问器使用更多本机内存比JNI内存要好,如果我们看到很多Java的话反射时,我们将希望使用JNI访问器。要做到这一点,我们只要需要将inflationThreshold属性设置为零。

如果你是在Oracle JVM上,那么你只需要设置:

-Dsun.reflect.inflationThreshold=2147483647

如果您在IBM JVM上,那么您需要设置:

-Dsun.reflect.inflationThreshold=0

请注意,这两个jvm的解释方式不同。

如果你是在Oracle JVM上,那么你只需要设置:

sun.reflect.inflationThreshold=2147483647 

如果您在IBM JVM上,那么您需要设置:

-Dsun.reflect.inflationThreshold=0

请注意,两个jvm的解释方式不同。

详细信息参考:

inflation_system_properties

本机内存使用

相关内容

  • 没有找到相关文章