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

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

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

    莊周夢蝶

    生活、程序、未來
       :: 首頁 ::  ::  :: 聚合  :: 管理

    兩段代碼的比較

    Posted on 2008-05-31 17:25 dennis 閱讀(2147) 評論(4)  編輯  收藏 所屬分類: java
    第一個程序:
    import java.util.ArrayList;
    import java.util.List;

    public class TailRecursionTest {
        
    public static void main(String[] args) {
            TailRecursionTest t 
    = new TailRecursionTest();
            
    for (int i = 0; i < 10000; i++)
                t.a(
    0);
        }

        
    public void a(int j) {
            j
    ++;
            List list 
    = new ArrayList<Integer>(100000);
            
    // 對list進行處理
        }
    }
        沒啥特殊的,僅僅是為了測試,我們將a方法調(diào)用10000次,a方法創(chuàng)建一個有100000個元素的list的局部變量。
    第二個程序:
    import java.util.ArrayList;
    import java.util.List;

    public class TailRecursionTest2 {
        
    public static void main(String[] args) {
            TailRecursionTest2 t 
    = new TailRecursionTest2();
            t.a(
    0);
        }

        
    public void a(int j) {
            System.out.println(j);
            j
    ++;
            
    if (j == 10000)
                
    return;
            List list 
    = new ArrayList<Integer>(100000);
            
    // 對list進行處理
            a(j);
        }
    }

        也沒啥特殊的,就是將循環(huán)換成了遞歸,a方法做的事情沒變。兩個都跑一下,程序1順利結(jié)束,程序2出問題了,啥問題?如下:
    161
    162
    163
    164
    165
    Exception in thread 
    "main" java.lang.OutOfMemoryError: Java heap space
        at java.util.ArrayList.
    <init>(Unknown Source)
        at TailRecursionTest2.a(TailRecursionTest2.java:
    17)
        at TailRecursionTest2.a(TailRecursionTest2.java:
    20)
        at TailRecursionTest2.a(TailRecursionTest2.java:
    20)
        at TailRecursionTest2.a(TailRecursionTest2.java:
    20)
        at TailRecursionTest2.a(TailRecursionTest2.java:
    20)
       我倒,才運行166次了,heap就滿了。問題在哪呢?oh,yep,你肯定想到了,是不是重復(fù)創(chuàng)建list這個大集合引起的呢?它不是局部變量嗎?怎么也會溢出?是的,list是局部變量,在a的方法棧里引用著,指向heap上的大對象,更關(guān)鍵的問題在于,java是沒有尾遞歸優(yōu)化的,遞歸方法是不會使用同一個棧幀,每一次遞歸調(diào)用,都將壓入新的棧幀,并且這個棧幀上又new了一個list變量,引用著heap上新的一個大集合。隨著棧深度的增加,jvm里維持著一條長長的方法調(diào)用軌跡以便你能回來,在方法沒有返回之前,這些list變量一直被各自的棧幀引用著,不能被GC,你說,能不OOM嗎?
        也許,你想到了個補救方法來挽救程序2,就是每次在處理完list后,我把它設(shè)置為null,不讓棧幀繼續(xù)引用著它,咱編寫對gc友好的代碼,這不就行了,試試:
    import java.util.ArrayList;
    import java.util.List;

    public class TailRecursionTest2 {
        
    public static void main(String[] args) {
            TailRecursionTest2 t 
    = new TailRecursionTest2();
            t.a(
    0);
        }

        
    public void a(int j) {
            System.out.println(j);
            j
    ++;
            
    if (j == 10000)
                
    return;
            List list 
    = new ArrayList<Integer>(100000);
            
    // 對list進行處理
            list = null;  //gc友好
            a(j);
        }
    }
        得意洋洋,我跑一下看看,這次跑到4000多次,但是:
    ......
    4289

    4290
    4291
    4292
    java.lang.StackOverflowError
        at sun.nio.cs.ext.DoubleByteEncoder.encodeArrayLoop(Unknown Source)
        at sun.nio.cs.ext.DoubleByteEncoder.encodeLoop(Unknown Source)
        at java.nio.charset.CharsetEncoder.encode(Unknown Source)
        沒辦法啊,人家sun的jdk就是不支持尾遞歸優(yōu)化,很不給你面子的棧溢出了。ibm的jdk據(jù)說支持尾遞歸優(yōu)化,上面這個程序在ibm的jdk上可能可以正常結(jié)束,未經(jīng)測試。

    總結(jié):在java里,遞歸最好咱還是別用,老老實實地while、for;就算遞歸了,最好遞歸方法不要new太大的對象,除非你能確定遞歸的深度不是那么大。


    評論

    # re: 兩段代碼的比較  回復(fù)  更多評論   

    2008-06-03 11:02 by 隔葉黃鶯
    幫博主在 IBM JDK1.4 下運行過
    第二個例子能運行到2700多
    第三個例子能順利執(zhí)行

    我也在 SUN JDK 1.6 試了一下
    第二個例子運行了 165
    第三個例子運行到 4292

    我在程序中基本不用遞歸,只在樹型結(jié)構(gòu)里用過,遞歸也不好理解。

    # re: 兩段代碼的比較  回復(fù)  更多評論   

    2008-06-03 14:16 by dennis
    @隔葉黃鶯
    ibm的jdk6是實現(xiàn)了尾遞歸優(yōu)化,這點可以確認。

    # re: 兩段代碼的比較  回復(fù)  更多評論   

    2008-06-04 00:25 by YODA
    總結(jié)寫的很好
    這個還算是很明顯的遞歸程序,有一次見過一個更狠的,JSP頁面動態(tài)include,好幾個頁面,最后搞出來一個include環(huán)(估計是好幾個人寫的),直接就StackOverFlow了。

    # re: 兩段代碼的比較  回復(fù)  更多評論   

    2012-07-08 18:27 by dys
    可以通過-xss 增加棧的深度吧
    主站蜘蛛池模板: 四虎永久免费观看| 亚洲国产天堂久久综合网站| 在线免费观看一级毛片| 成年女性特黄午夜视频免费看| 成年人网站在线免费观看| 国产三级免费观看| 亚洲日本中文字幕| 亚洲中文字幕久久精品无码A | 人禽伦免费交视频播放| 国产色爽免费无码视频| 免费国产作爱视频网站| 国产gav成人免费播放视频| 亚洲国产三级在线观看| 亚洲 欧洲 日韩 综合在线| 色婷婷综合缴情综免费观看| 在线观看免费无码专区| 中文字幕影片免费在线观看| 亚洲视频在线一区二区| 亚洲一区中文字幕在线观看| 成人福利在线观看免费视频| 亚洲电影免费观看| 亚洲成AV人片一区二区密柚| 亚洲国产精品不卡在线电影| 麻豆69堂免费视频| 成人免费毛片内射美女-百度| 亚洲乱码中文字幕久久孕妇黑人| 亚洲一卡二卡三卡四卡无卡麻豆| 视频免费1区二区三区| 成人免费视频国产| 亚洲精品久久无码| www.黄色免费网站| 亚洲制服在线观看| 国产在线观看麻豆91精品免费 | 久久精品a一国产成人免费网站| 亚洲精品乱码久久久久久蜜桃不卡| 亚洲一区二区三区写真| 久久精品a一国产成人免费网站| 亚洲欧洲日韩在线电影| 91青青青国产在观免费影视| 亚洲av日韩av激情亚洲| 免费无码又爽又刺激高潮视频 |