方法區(qū)和運(yùn)行時(shí)常量池溢出

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ì)視為不同的類)等。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容