在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
方法區溢出也是一種常見的內存溢出異常,一個類要被垃圾收集器回收掉,斷定條件是比較苛刻的。在常常動態生成大量Class的應用中,須要特別注意類的回收情況。這類場景除了上面提到的程序使用了CGLib字節碼加強和動態語言以外,常見的還有:大量JSP或動態產生JSP文件的應用(JSP第一次運行時須要編譯爲Java類)、基於OSGi的應用(即便是同一個類文件,被不一樣的加載器加載也會視爲不一樣的類)等。code
在jdk1.7之後,perm持久代已經被移除,常量池也放到了堆中,其致使的溢出也變成了堆溢出。xml
示例見《JVM體系結構之七:持久代、元空間(Metaspace) Metaspace 之三--瞭解String類的intern()方法、常量池介紹、常量池從Perm-->Heap》htm
見《JVM體系結構之三:方法區之2(jdk1.6,jdk1.7,jdk1.8下的方法區變遷)》
上面示例2在jdk8中運行,因爲方法區被移除了,那麼經過反射生成的一系列對象存放到哪兒了?可看到jvisualVM中的元空間不斷增加。