Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java.lang.OutOfMemoryError: PermGen space: java reflection

I use java reflection in the code like this:

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

I use jprofiler can see many class like this sun.reflect.GeneratedMethodAccessor11

these classes are increased per call

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

I think this is why PermGen space increase, how to clean these classes?

like image 215
Fatkun Avatar asked Apr 21 '13 10:04

Fatkun


People also ask

What causes PermGen space error?

OutOfMemoryError: PermGen Space is a runtime error in Java which occurs when the permanent generation (PermGen) area in memory is exhausted. The PermGen area of the Java heap is used to store metadata such as class declarations, methods and object arrays.

What is the replacement for PermGen space in Java?

In the place of PermGen, a new feature called Meta Space has been introduced. MetaSpace grows automatically by default. Here, the garbage collection is automatically triggered when the class metadata usage reaches its maximum metaspace size. It is removed from java 8.

How can we avoid OutOfMemoryError in Java?

OutOfMemoryError: Metaspace error is thrown. To mitigate the issue, you can increase the size of the Metaspace by adding the -XX:MaxMetaspaceSize flag to startup parameters of your Java application. For example, to set the Metaspace region size to 128M, you would add the following parameter: -XX:MaxMetaspaceSize=128m .


2 Answers

There is a pretty nice article discussing about potential native memory use in reflection delegating classloaders.

When using Java reflection, the JVM has two methods of accessing the information on the class being reflected. It can use a JNI accessor, or a Java bytecode accessor. If it uses a Java bytecode accessor, then it needs to have its own Java class and classloader (sun/reflect/GeneratedMethodAccessor class and sun/reflect/DelegatingClassLoader). Theses classes and classloaders use native memory. The accessor bytecode can also get JIT compiled, which will increase the native memory use even more. If Java reflection is used frequently, this can add up to a significant amount of native memory use. The JVM will use the JNI accessor first, then after some number of accesses on the same class, will change to use the Java bytecode accessor. This is called inflation, when the JVM changes from the JNI accessor to the bytecode accessor. Fortunately, we can control this with a Java property. The sun.reflect.inflationThreshold property tells the JVM what number of times to use the JNI accessor. If it is set to 0, then the JNI accessors are always used. Since the bytecode accessors use more native memory than the JNI ones, if we are seeing a lot of Java reflection, we will want to use the JNI accessors. To do this, we just need to set the inflationThreshold property to zero.

If you are on a Oracle JVM then you would only need to set:

-Dsun.reflect.inflationThreshold=2147483647

If you are on IBM JVM, then you would need to set:

-Dsun.reflect.inflationThreshold=0

Please note that both JVMs differ in the way they interpret.

like image 179
StarPinkER Avatar answered Sep 19 '22 16:09

StarPinkER


If you are on a Oracle JVM then you would only need to set:

sun.reflect.inflationThreshold=2147483647 

If you are on IBM JVM, then you would need to set:

-Dsun.reflect.inflationThreshold=0

Please note that both JVMs differ in the way they interpret.

Reference for more details:

inflation_system_properties

native memory use

like image 41
PraveenKumar Katwe Avatar answered Sep 21 '22 16:09

PraveenKumar Katwe