7

我在这样的代码中使用 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 空间增加的原因,如何清理这些类?

4

2 回答 2

12

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

当使用 Java 反射时,JVM 有两种方法可以访问被反射的类的信息。它可以使用 JNI 访问器或 Java 字节码访问器。如果它使用 Java 字节码访问器,那么它需要有自己的 Java 类和类加载器(sun/reflect/GeneratedMethodAccessor 类和 sun/reflect/DelegatingClassLoader)。这些类和类加载器使用本机内存。访问器字节码也可以进行 JIT 编译,这将进一步增加本机​​内存的使用。如果频繁使用 Java 反射,这可能会增加大量的本机内存使用量。JVM 将首先使用 JNI 访问器,然后在对同一类进行一定次数的访问后,将更改为使用 Java 字节码访问器。这称为通货膨胀,当 JVM 从 JNI 访问器更改为字节码访问器时。幸运的是,我们可以使用 Java 属性来控制它。sun.reflect.inflationThreshold 属性告诉 JVM 使用 JNI 访问器的次数。如果设置为 0,则始终使用 JNI 访问器。由于字节码访问器比 JNI 访问器使用更多的本机内存,如果我们看到大量 Java 反射,我们将希望使用 JNI 访问器。为此,我们只需要将通货膨胀阈值属性设置为零。

如果您使用的是 Oracle JVM,那么您只需要设置:

-Dsun.reflect.inflationThreshold=2147483647

如果您使用的是 IBM JVM,那么您需要设置:

-Dsun.reflect.inflationThreshold=0

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

于 2013-04-21T12:02:29.430 回答
2

如果您使用的是 Oracle JVM,那么您只需要设置:

sun.reflect.inflationThreshold=2147483647 

如果您使用的是 IBM JVM,那么您需要设置:

-Dsun.reflect.inflationThreshold=0

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

更多细节参考:

通货膨胀系统属性

本机内存使用

于 2016-06-02T14:20:04.863 回答