JVM異常之:方法區溢出OutOfMemoryError: PermGen space JVM體系結構之三:方法區之2(jdk1.6,jdk1.7,jdk1.8下的方法區變遷)

一、方法區溢出(Perm持久代溢出)

 在jdk1.6及以前的版本中,常量池放在Perm區也便是方法區中,因此在jdk1.6版本中,常量池溢出能夠說是方法區溢出。html

示例一:java

方法區溢出的示例見《JVM體系結構之七:持久代、元空間(Metaspace) Metaspace 之三--瞭解String類的intern()方法、常量池介紹、常量池從Perm-->Heap網絡

 

示例二:jvm

在網絡上看到一個cglib致使的方法區溢出的示例:藉助CGLib使方法區出現內存溢出異常(在對類進行加強時,都會使用到CGLib這類字節碼技術,加強的類越多,就須要越大的方法區來保證動態生成的Class能夠加載入內存。另外,JVM上的動態語言(例如Groovy等)一般都會持續建立類來實現語言的動態性,隨着這類語言的流行,也愈來愈容易遇到與下面代碼類似的溢出場景)post

pom.xml中增長cglib:url

      <dependency>
          <groupId>cglib</groupId>
          <artifactId>cglib</artifactId>
          <version>3.2.6</version>
      </dependency>

 

package com.dxz.jvm;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
 * @VM args : -XX:PermSize=10M -XX:MaxPermSize=10M
 */
public class MethodAreaOutOfMemory {

    public static void main(String[] args) {
        while (true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(MethodAreaOutOfMemory.TestObject.class);
            enhancer.setUseCache(false);
            enhancer.setCallback(new MethodInterceptor() {
                public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
                    return arg3.invokeSuper(arg0, arg2);
                }
            });
            enhancer.create();
        }
    }

    public static class TestObject {
        private double a = 34.53;
        private Integer b = 9999999;
    }
}

運行結果:spa

  1. Caused by: java.lang.OutOfMemoryError: PermGen space  
  2. at java.lang.ClassLoader.defineClass1(Native Method)  
  3. at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)  
  4. at java.lang.ClassLoader.defineClass(ClassLoader.java:616)  
  5. ... 8 more 

方法區溢出也是一種常見的內存溢出異常,一個類要被垃圾收集器回收掉,斷定條件是比較苛刻的。在常常動態生成大量Class的應用中,須要特別注意類的回收情況。這類場景除了上面提到的程序使用了CGLib字節碼加強和動態語言以外,常見的還有:大量JSP或動態產生JSP文件的應用(JSP第一次運行時須要編譯爲Java類)、基於OSGi的應用(即便是同一個類文件,被不一樣的加載器加載也會視爲不一樣的類)等。code

2、常量池致使的堆溢出

在jdk1.7之後,perm持久代已經被移除,常量池也放到了堆中,其致使的溢出也變成了堆溢出。xml

示例見《JVM體系結構之七:持久代、元空間(Metaspace) Metaspace 之三--瞭解String類的intern()方法、常量池介紹、常量池從Perm-->Heaphtm

 

3、jdk1.8後,方法區被移除了

見《JVM體系結構之三:方法區之2(jdk1.6,jdk1.7,jdk1.8下的方法區變遷)

上面示例2在jdk8中運行,因爲方法區被移除了,那麼經過反射生成的一系列對象存放到哪兒了?可看到jvisualVM中的元空間不斷增加。

 

相關文章
相關標籤/搜索