<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    ALL is Well!

    敏捷是一條很長的路,摸索著前進著

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      30 隨筆 :: 23 文章 :: 71 評論 :: 0 Trackbacks

    cglib版本為cglib-nodep-2.2.jar.
    本次只為演示在使用中出現(xiàn)的Java內(nèi)存泄漏的問題,以及如何解決這樣的問題。
    cglib的應用是非常多的,但是當我們使用它的時候,如果一不小心,等出了問題再去查,就比較杯具了。所以最好的解決方案就是寫代碼時就注意這些細節(jié)。(當然了,不能指望在開發(fā)階段不引入Bug)
    近期項目在做壓力測試,暴露了內(nèi)存泄漏的Bug,cglib的使用不當便是原因之一。
    下面來介紹代碼。
    清單1:

     1package com.jn.proxy;
     2
     3import java.lang.reflect.Method;
     4
     5import net.sf.cglib.proxy.Callback;
     6import net.sf.cglib.proxy.CallbackFilter;
     7import net.sf.cglib.proxy.Enhancer;
     8import net.sf.cglib.proxy.MethodInterceptor;
     9import net.sf.cglib.proxy.MethodProxy;
    10import net.sf.cglib.proxy.NoOp;
    11
    12/**
    13 * 步驟方法攔截器.<br>
    14 * 
    15 */

    16public class CglibLeak1 {
    17
    18    public <T> T newProxyInstance(Class<T> clazz) {
    19        return newProxyInstance(clazz, new MyInterceptor(), new MyFilter());
    20    }

    21
    22    /**
    23     * 創(chuàng)建一個類動態(tài)代理.
    24     * 
    25     * @param <T>
    26     * @param superclass
    27     * @param methodCb
    28     * @param callbackFilter
    29     * @return
    30     */

    31    public static <T> T newProxyInstance(Class<T> superclass, Callback methodCb, CallbackFilter callbackFilter) {
    32        Enhancer enhancer = new Enhancer();
    33        enhancer.setSuperclass(superclass);
    34        enhancer.setCallbacks(new Callback[] { methodCb, NoOp.INSTANCE });
    35        enhancer.setCallbackFilter(callbackFilter);
    36
    37        return (T) enhancer.create();
    38    }

    39    
    40    /**
    41     * 實現(xiàn)MethodInterceptor接口
    42     * 
    43     * @author l
    44     *
    45     */

    46    class MyInterceptor implements MethodInterceptor {
    47        @Override
    48        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
    49            throws Throwable {
    50            return null;
    51        }

    52    }

    53    
    54    /**
    55     * 實現(xiàn)CallbackFilter接口
    56     * 
    57     * @author l
    58     */

    59    class MyFilter implements CallbackFilter {
    60        @Override
    61        public int accept(Method method) {
    62            // Do some thing
    63            return 1;
    64        }

    65    }

    66    
    67    /**
    68     * 測試代碼
    69     * @param args
    70     * @throws InterruptedException
    71     */

    72    public static void main(String args[]) throws InterruptedException {
    73        CglibLeak1 leak = new CglibLeak1();
    74        int count = 0;
    75        while(true{
    76            leak.newProxyInstance(Object.class); // 為了測試縮寫
    77            Thread.sleep(100);
    78            System.out.println(count++);
    79        }

    80    }

    81}

    用JProfiler來觀察內(nèi)存對象情況。
    運行了一段時間(幾十秒鐘吧),內(nèi)存對象的情況如圖所示:

    我們看到 MyFilter 的Instance count 已經(jīng)達到了1266個,而且隨著程序的繼續(xù)運行,Instance count還在不斷飆升,此情此景讓人心寒。
    而且在JProfiler上點擊 Run GC 按鈕 這些對象并不會被回收。內(nèi)存泄漏啦。

    原因就是cglib自身的內(nèi)部代理類緩存,將MyFilter對象加入到了緩存中,以至于該對象很大、并發(fā)量很大時,會造成內(nèi)存溢出的Bug。

    既然知道了原因,解決辦法就很明顯了。
    1.重寫MyFilter類的equals和hashCode方法,這樣,當MyFilter對象準備進入緩存時,cglib會判斷是否為不同的MyFilter對象,如果是才加入到緩存。
    我們重寫了equals和hashCode后,讓cglib認為這些MyFilter對象都是相同的。
    2.將MyFilter類設置為靜態(tài)類。原理都是相同的。

    我以第二種解決方案來修改代碼,請看。
    清單2:
    package com.jn.proxy;

    import java.lang.reflect.Method;

    import net.sf.cglib.proxy.Callback;
    import net.sf.cglib.proxy.CallbackFilter;
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    import net.sf.cglib.proxy.NoOp;

    /**
     * 步驟方法攔截器.<br>
     
    */

    public class CglibLeak {

        
    private static MethodInterceptor myInterceptor = new MethodInterceptor() {
                                                           @Override
                                                           
    public Object intercept(Object obj,
                                                               Method method, Object[] args,
                                                               MethodProxy proxy) 
    throws Throwable {
                                                               
    // do some things
                                                               return null;
                                                           }

                                                       }
    ;
                                                       
    // 創(chuàng)建實例
        private static CallbackFilter    myFilter      = new MyFilter();

        
    public static <T> T newProxyInstance(Class<T> clazz) {
            
    return newProxyInstance(clazz, myInterceptor, myFilter);
        }


        
    /**
         * 實現(xiàn)CallbackFilter接口
         * 
         * 
    @author l
         
    */

        
    static class MyFilter implements CallbackFilter {
            @Override
            
    public int accept(Method method) {
                
    // Do some thing
                return 1;
            }

        }


        
    /**
         * 創(chuàng)建一個類動態(tài)代理.
         * 
         * 
    @param <T>
         * 
    @param superclass
         * 
    @param methodCb
         * 
    @param callbackFilter
         * 
    @return
         
    */

        
    public static <T> T newProxyInstance(Class<T> superclass, Callback methodCb,
            CallbackFilter callbackFilter) 
    {
            Enhancer enhancer 
    = new Enhancer();
            enhancer.setSuperclass(superclass);
            enhancer.setCallbacks(
    new Callback[]{methodCb, NoOp.INSTANCE});
            enhancer.setCallbackFilter(callbackFilter);

            
    return (T)enhancer.create();
        }


        
    /**
         * 測試代碼
         * 
         * 
    @param args
         * 
    @throws InterruptedException
         
    */

        
    public static void main(String args[]) throws InterruptedException {
            
    int count = 0;
            
    while (true{
                newProxyInstance(Object.
    class); // 為了測試縮寫
                Thread.sleep(100);
                System.out.println(count
    ++);
            }

        }

    }


    運行后的結(jié)果應該很明顯了:


    MyFilter的Instance count 一直為1.
    問題解決了。

    因為我的MyFilter類中沒有成員變量,所以在多線程并發(fā)訪問時也不會出現(xiàn)問題。

    如果以方案1 來解決這個內(nèi)存泄漏問題情況是怎樣的呢?
    清單3:
    package com.jn.proxy;

    import java.lang.reflect.Method;

    import net.sf.cglib.proxy.Callback;
    import net.sf.cglib.proxy.CallbackFilter;
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    import net.sf.cglib.proxy.NoOp;

    /**
     * 步驟方法攔截器.<br>
     
    */

    public class CglibLeak {

        
    private static MethodInterceptor myInterceptor = new MethodInterceptor() {
                                                           @Override
                                                           
    public Object intercept(Object obj,
                                                               Method method, Object[] args,
                                                               MethodProxy proxy) 
    throws Throwable {
                                                               
    // do some things
                                                               return null;
                                                           }

                                                       }
    ;

        
    public <T> T newProxyInstance(Class<T> clazz) {
            
    return newProxyInstance(clazz, myInterceptor, new MyFilter());
        }


        
    /**
         * 實現(xiàn)CallbackFilter接口
         * 
         * 
    @author l
         
    */

        
    class MyFilter implements CallbackFilter {
            @Override
            
    public int accept(Method method) {
                
    // Do some thing
                return 1;
            }


            @Override
            
    public boolean equals(Object o) {
                
    if (o instanceof MyFilter) {
                    
    return true;
                }

                
    return false;
            }


            @Override
            
    public int hashCode() {
                
    return 10011// 沒什么原則,只為測試
            }

        }


        
    /**
         * 創(chuàng)建一個類動態(tài)代理.
         * 
         * 
    @param <T>
         * 
    @param superclass
         * 
    @param methodCb
         * 
    @param callbackFilter
         * 
    @return
         
    */

        
    public static <T> T newProxyInstance(Class<T> superclass, Callback methodCb,
            CallbackFilter callbackFilter) 
    {
            Enhancer enhancer 
    = new Enhancer();
            enhancer.setSuperclass(superclass);
            enhancer.setCallbacks(
    new Callback[]{methodCb, NoOp.INSTANCE});
            enhancer.setCallbackFilter(callbackFilter);

            
    return (T)enhancer.create();
        }


        
    /**
         * 測試代碼
         * 
         * 
    @param args
         * 
    @throws InterruptedException
         
    */

        
    public static void main(String args[]) throws InterruptedException {
            CglibLeak l 
    = new CglibLeak();
            
    int count = 0;
            
    while (true{
                l.newProxyInstance(Object.
    class); // 為了測試縮寫
                Thread.sleep(100);
                System.out.println(count
    ++);
            }

        }

    }


    運行一段時間后(幾十秒),JProfiler的觀測結(jié)果為:

    MyFilter的對象還是很多,這是不是就表明 內(nèi)存泄漏的問題依然存在呢。
    當然不是,因為JVM垃圾回收策略的原因,我們new出來的MyFilter對象并不是 一旦成為垃圾就立即 被回收的。
    經(jīng)觀察,當Instance count 為600左右時,GC會將這些“垃圾”回收。

    解決問題之際感慨一下:Java內(nèi)存問題無處不在啊。

    本文為原創(chuàng),歡迎轉(zhuǎn)載,轉(zhuǎn)載請注明出處BlogJava
    posted on 2010-09-09 17:00 李 明 閱讀(3674) 評論(1)  編輯  收藏

    評論

    # re: cglib使用不慎引發(fā)的Java內(nèi)存泄漏 2010-09-09 20:16 pxb

    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(Object.class);
    enhancer.setCallbacks(new Callback[]{methodCb, NoOp.INSTANCE});
    enhancer.setCallbackFilter(callbackFilter);

    while (true) {
    enhancer.create();
    Thread.sleep(100);
    System.out.println(count++);
    }  回復  更多評論
      


    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導航:
     
    主站蜘蛛池模板: 丰满亚洲大尺度无码无码专线| 国产一卡二卡四卡免费| 亚洲依依成人亚洲社区| 亚洲av永久无码精品古装片| 免费很黄很色裸乳在线观看| 在线观看视频免费完整版| 久久国产乱子精品免费女| 免费一区二区无码视频在线播放| 亚洲中文字幕无码亚洲成A人片| 亚洲美女视频免费| 亚洲AV无码一区二区三区系列| 亚洲成a人一区二区三区| 免费看的成人yellow视频| 国产一精品一AV一免费孕妇| 亚洲毛片免费视频| 四虎1515hh永久久免费| 最近高清中文字幕免费| 免费人妻无码不卡中文字幕系| 国产一区二区三区免费观看在线| 一本久久免费视频| 一级特黄aaa大片免费看| 日韩精品亚洲专区在线影视| 亚洲精品色播一区二区| 亚洲一区二区三区成人网站 | 成人a毛片视频免费看| 国产午夜亚洲精品国产| 国产精品亚洲四区在线观看 | 在线观看日本免费a∨视频| 24小时在线免费视频| 亚洲黄色免费网站| 黄页网站免费在线观看| 亚洲中文无码永久免费| 最新中文字幕电影免费观看| AV免费网址在线观看| 日韩在线免费看网站| 国产在线19禁免费观看| 亚洲精品国产精品国自产观看| 亚洲国产精品一区二区第四页| 亚洲综合色在线观看亚洲| 国产亚洲精品a在线观看app | 精品久久8x国产免费观看|