<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 增加棧的深度吧
    主站蜘蛛池模板: 18女人水真多免费高清毛片| 九九全国免费视频| 69视频免费在线观看| 亚洲精品无码av人在线观看 | 亚洲中文字幕在线乱码| 理论秋霞在线看免费| 无码不卡亚洲成?人片| 美景之屋4在线未删减免费 | 无码永久免费AV网站| 亚洲无成人网77777| 久久久久久国产a免费观看黄色大片 | 久久狠狠高潮亚洲精品| 国产精品永久免费10000| 456亚洲人成影院在线观| 免费无码又爽又刺激毛片| 亚洲AV永久无码精品放毛片| 国产国产成年年人免费看片| 又长又大又粗又硬3p免费视频| 亚洲一区二区视频在线观看 | 最近中文字幕无免费视频| 亚洲日韩精品A∨片无码加勒比| 永久在线毛片免费观看| 一个人看的www在线免费视频 | 国产乱弄免费视频| 一级做a毛片免费视频| 久久精品国产亚洲一区二区| 88av免费观看| 亚洲欧美日韩中文无线码| 亚洲成人影院在线观看| 国产成人AV免费观看| 亚洲精品午夜国产va久久| 亚洲AV中文无码乱人伦在线视色| 久久福利青草精品资源站免费 | 亚洲人成网站在线播放影院在线| 999在线视频精品免费播放观看| 色偷偷噜噜噜亚洲男人| 中文字幕不卡亚洲| 中文字幕影片免费在线观看| 黄色片网站在线免费观看| 亚洲一区二区电影| 国产无遮挡又黄又爽免费视频 |