1、運(yùn)行時(shí)常量池是方法區(qū)的一部分,方法區(qū)用于存放class的相關(guān)信息,如類名、訪問(wèn)修飾符、常量池、字段描述、方法描述等。對(duì)于這個(gè)區(qū)域的測(cè)試,基本思路是運(yùn)行時(shí)產(chǎn)生大量的類去填滿方法區(qū),知道溢出。雖然直接使用Java SE API也可以動(dòng)態(tài)產(chǎn)生類(如反射時(shí)的GeneratedConstructorAccessor和動(dòng)態(tài)代理等),但在本次試驗(yàn)使用CGLIB直接操作字節(jié)碼運(yùn)行時(shí),生成大量的動(dòng)態(tài)類。值得注意的是,當(dāng)前主流的很多框架 如:Spring,Hibernate對(duì)類進(jìn)行增強(qiáng)時(shí),都會(huì)使用到類似CGLIB這類字節(jié)碼技術(shù),增強(qiáng)的類越多,就需要越大的方法區(qū)來(lái)保證動(dòng)態(tài)生成的Class可以加載如內(nèi)存。
測(cè)試代碼:
public class JavaMethodAreaOOM {
public static void main(String[] args){
while (true){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOMObject.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
return methodProxy.invokeSuper(o,objects);
}
});
enhancer.create();
}
}
static class OOMObject{
}
}
修改虛擬機(jī)參數(shù):
-XX:PermSize分配非堆最小內(nèi)存,默認(rèn)為物理內(nèi)存的1/64;
-XX:MaxPermSize分配最大內(nèi)存,默認(rèn)為物理內(nèi)存的1/4。
筆者嘗試在java 1.8下運(yùn)行發(fā)現(xiàn),一直沒(méi)有報(bào)錯(cuò)信息出現(xiàn),直到電腦內(nèi)存占完。
查詢后得知:
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=10m; support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=10m; support was removed in 8.0
在java 1.8中取消了這兩個(gè)參數(shù)。
然后筆者嘗試在java 1.7下運(yùn)行,測(cè)試結(jié)果如下:
Exception in thread "main"
Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "main"
報(bào)出內(nèi)存溢出的錯(cuò)誤,但是沒(méi)有PermGen Space的說(shuō)明,添加參數(shù)
-XX:+TraceClassLoading -XX:+TraceClassUnloading
可以查看增加的class文件來(lái)源:
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_159 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_160 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_161 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_162 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_163 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_164 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_165 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_166 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_167 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_168 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_169 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_170 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_171 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_172 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_173 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_174 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_175 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_176 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_177 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_178 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_179 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_180 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_181 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_182 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_183 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_184 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_185 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_186 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_187 from file:/E:/study/myCode/Jvm/target/classes/]
[Loaded com.example.outofmemoryerror.JavaMethodAreaOOM$OOMObject$$EnhancerByCGLIB$$df19c91_188 from file:/E:/study/myCode/Jvm/target/classes/]
可以看到,程序不斷地加載一個(gè)類,同時(shí)會(huì)增加該類的各種信息,直至填充方法區(qū),拋出錯(cuò)誤。
方法區(qū)溢出也是一種常見(jiàn)的內(nèi)存溢出異常,一個(gè)類要被垃圾收集器回收掉,判定條件是比較苛刻的。在經(jīng)常動(dòng)態(tài)生成大量Class的應(yīng)用中,需要特別注意類的回收狀況。這類場(chǎng)景除了上面提到的程序使用了CGLib字節(jié)碼增強(qiáng)和動(dòng)態(tài)語(yǔ)言之外,常見(jiàn)的還有:大量JSP或動(dòng)態(tài)產(chǎn)生JSP文件的應(yīng)用(JSP第一次運(yùn)行時(shí)需要編譯為Java類)、基于OSGi的應(yīng)用(即使是同一個(gè)類文件,被不同的加載器加載也會(huì)視為不同的類)等。