于吉吉的技術(shù)博客

          建造高性能門戶網(wǎng)

            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            65 隨筆 :: 6 文章 :: 149 評(píng)論 :: 0 Trackbacks

          上段時(shí)間有臺(tái)機(jī)器發(fā)生了 java.lang.OutOfMemoryError: PermGen space 內(nèi)存溢出的異常,當(dāng)時(shí)大概判斷了原因后就把 MaxPermSize 配置調(diào)高后,就把問題解決了,不過空下時(shí)間后還是需要繼續(xù)把review代碼。

          一般來說PermSize Space OOM的話,第一種可能就是方法區(qū)溢出,第二種就是運(yùn)行時(shí)常量池溢出,第二種查看后基本排除掉,問題就應(yīng)該出現(xiàn)在方法區(qū)的溢出,方法區(qū)用于存放class的相關(guān)信息,如類名,訪問修飾符,常量池,字段描述,方法描述等等,對(duì)于這個(gè)區(qū)域的溢出,基本上都是運(yùn)行時(shí)產(chǎn)生大量的類填滿了整個(gè)方法區(qū),直到溢出。

          spring aop中都是使用到了cglib這類字節(jié)碼的技術(shù),動(dòng)態(tài)代理的類越多,就需要越多的方法區(qū)來保證動(dòng)態(tài)生成的class可以加載入到內(nèi)存中去,
          不過spring框架導(dǎo)致的不會(huì)因?yàn)檫@種原因。撐爆perm的應(yīng)該是各種methodaccessorX和constructoracccessorX等等。本來這些accessor也有緩存,但它們使用內(nèi)存大小敏感的reference引用著的,且使用的是堆內(nèi)存。當(dāng)你堆內(nèi)存吃緊的時(shí)候,這些緩存就摧毀了,就必然會(huì)不斷產(chǎn)生新的methodAccessor字節(jié)碼,是這個(gè)撐爆了perm。所以除增大permsize還應(yīng)該看看平時(shí)運(yùn)行時(shí)堆內(nèi)存是不是經(jīng)常用光

          下面的例使用cglib直接進(jìn)行動(dòng)態(tài)代理產(chǎn)生大量的動(dòng)態(tài)類,然后使用jconsole進(jìn)行觀察。

          首先將本機(jī)的jvm配置為 -XX:PermSize=64M -XX:MaxPermSize=64M ,給到PermSize最大為64M的內(nèi)存

          public class PermgenOOM {

              
          public static void main(String[] args) throws InterruptedException {
                  
          int i=0;
                  
          while(true){
                      Enhancer enhancer 
          = new Enhancer();
                      enhancer.setSuperclass(Product.
          class);
                      enhancer.setUseCache(
          false);// 關(guān)閉CGLib緩存,否則總是生成同一個(gè)類
                      enhancer.setCallback(new MethodInterceptor() {                
                          @Override
                          
          public Object intercept(Object obj, Method method, Object[] args,
                                  MethodProxy methodproxy) 
          throws Throwable {
                              
          // TODO Auto-generated method stub
                              return methodproxy.invokeSuper(obj,args);
                          }
                      });
                      enhancer.create();
                      Thread.sleep(
          100);
                  }
              }
          }

          很快,系統(tǒng)就拋出了 java.lang.OutOfMemoryError: PermGen space
          內(nèi)存池peimgen的情況


          加載類的情況



          并且在方法區(qū)中,一個(gè)類如果要被垃圾收集器回收掉,判斷的條件是非常苛刻的,很多人都把方法區(qū)稱為“永久區(qū)”(Permanent Generation),但據(jù)說2者在本質(zhì)上是不一致的,另外還有稱呼為“非堆區(qū)”,不糾結(jié)這個(gè)了。

          再看看enhancer.setUseCache(false),如果選擇為true的話,那么就使用和更新一類具有相同屬性生成的類的靜態(tài)緩存,而不會(huì)在同一個(gè)類文件還繼續(xù)被動(dòng)態(tài)加載并視為不同的類,這個(gè)其實(shí)跟類的equals()和hashCode()有關(guān),它們是與cglib內(nèi)部的class cache的key相關(guān)的。

          將上面的程序 enhancer.setUseCache(false) 改為 enhancer.setUseCache(ture)

          public class PermgenOOM {

              
          public static void main(String[] args) throws InterruptedException {
                  
          int i=0;
                  
          while(true){
                      Enhancer enhancer 
          = new Enhancer();
                      enhancer.setSuperclass(Product.
          class);
                      enhancer.setUseCache(
          true);// 或者不寫,默認(rèn)值就是true
                      enhancer.setCallback(new MethodInterceptor() {                
                          @Override
                          
          public Object intercept(Object obj, Method method, Object[] args,
                                  MethodProxy methodproxy) 
          throws Throwable {
                              
          // TODO Auto-generated method stub
                              return methodproxy.invokeSuper(obj,args);
                          }
                      });
                      enhancer.create();
                      Thread.sleep(
          100);
                  }
              }
          }

          內(nèi)存池peimgen的情況


          加載類的情況



          可以發(fā)現(xiàn)內(nèi)存池peimgen和加載類的情況并沒有呈現(xiàn)直線上漲,已經(jīng)他們一直都使用者動(dòng)態(tài)類生成類的靜態(tài)緩存,但是這種動(dòng)態(tài)創(chuàng)建類使用靜態(tài)緩存在一些情況下并不適合需求。


          posted on 2011-08-21 15:55 陳于喆 閱讀(6437) 評(píng)論(0)  編輯  收藏 所屬分類: web開發(fā)java
          主站蜘蛛池模板: 南郑县| 繁昌县| 房产| 包头市| 昭觉县| 会昌县| 高清| 长岛县| 广安市| 崇礼县| 鄂托克前旗| 庄河市| 绥化市| 巨野县| 定陶县| 永福县| 南召县| 绩溪县| 丰镇市| 北辰区| 昔阳县| 错那县| 横山县| 宣汉县| 襄樊市| 长治县| 乃东县| 资溪县| 阿瓦提县| 靖边县| 平邑县| 格尔木市| 田阳县| 霍州市| 菏泽市| 花莲县| 牙克石市| 辰溪县| 阿拉尔市| 齐齐哈尔市| 仁寿县|