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

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

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

    ALL is Well!

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

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

    cglib版本為cglib-nodep-2.2.jar.
    本次只為演示在使用中出現的Java內存泄漏的問題,以及如何解決這樣的問題。
    cglib的應用是非常多的,但是當我們使用它的時候,如果一不小心,等出了問題再去查,就比較杯具了。所以最好的解決方案就是寫代碼時就注意這些細節。(當然了,不能指望在開發階段不引入Bug)
    近期項目在做壓力測試,暴露了內存泄漏的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     * 創建一個類動態代理.
    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     * 實現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     * 實現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來觀察內存對象情況。
    運行了一段時間(幾十秒鐘吧),內存對象的情況如圖所示:

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

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

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

    我以第二種解決方案來修改代碼,請看。
    清單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;
                                                           }

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

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


        
    /**
         * 實現CallbackFilter接口
         * 
         * 
    @author l
         
    */

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

        }


        
    /**
         * 創建一個類動態代理.
         * 
         * 
    @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
    ++);
            }

        }

    }


    運行后的結果應該很明顯了:


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

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

    如果以方案1 來解決這個內存泄漏問題情況是怎樣的呢?
    清單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());
        }


        
    /**
         * 實現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// 沒什么原則,只為測試
            }

        }


        
    /**
         * 創建一個類動態代理.
         * 
         * 
    @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的觀測結果為:

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

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

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

    評論

    # re: cglib使用不慎引發的Java內存泄漏 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++);
    }  回復  更多評論
      


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


    網站導航:
     
    主站蜘蛛池模板: 亚洲精品无码成人片久久不卡| 黄网站色视频免费看无下截| 在线a人片天堂免费观看高清| 综合一区自拍亚洲综合图区| 久久精品夜色噜噜亚洲A∨| 精品无码国产污污污免费网站 | 无码免费又爽又高潮喷水的视频| 亚洲日韩精品射精日| 久久受www免费人成_看片中文| 直接进入免费看黄的网站| 亚洲成Av人片乱码色午夜| 成人毛片免费观看| 国产一级婬片A视频免费观看| 亚洲人成片在线观看| 亚洲一级片内射网站在线观看| 四虎免费影院ww4164h| 香蕉国产在线观看免费| 亚洲精品成人久久| 亚洲国产人成中文幕一级二级| 在线免费观看国产| 一级毛片视频免费| 狠狠色香婷婷久久亚洲精品| 国产亚洲人成A在线V网站| 歪歪漫画在线观看官网免费阅读 | 久久国产精品免费一区二区三区| 亚洲人成网网址在线看| 亚洲欧洲∨国产一区二区三区 | 国产亚洲美女精品久久久2020| 免费无码AV电影在线观看 | 精品亚洲一区二区三区在线观看 | 亚洲阿v天堂在线2017免费| 亚洲免费一级视频| 国产婷婷成人久久Av免费高清| 国产精品亚洲精品日韩动图| 亚洲国产精品人久久电影| 亚洲线精品一区二区三区影音先锋 | 性生大片视频免费观看一级| 日本亚洲色大成网站www久久| 亚洲精品在线免费观看视频| 亚洲精品制服丝袜四区| 亚洲成AV人网址|