遞迴呼叫 VS 迴圈呼叫

zhuguowei2發表於2019-01-19

現象

有一個方法 邏輯如下

  • 分批查詢state=0的資料 每次500條
  • 做一些處理後 修改state狀態 state=0 ==> state=1 表示已經處理過了
  • 遞迴呼叫 直到查不出資料來

發現當資料量大的時候 如有幾萬條資料待處理 很容易發生記憶體溢位的問題 覺得很奇怪 不是每次限制只查500條嗎 怎麼還會有記憶體溢位的問題呢?

假設
遞迴呼叫不會釋放區域性變數 直到方法呼叫結束

證明

@Test
public void recursiveCall(){
    foo(1);
}

private void foo(int i){
    // 區域性變數 佔用1M
    byte[] a = new byte[1 * 1024 * 1024];
    System.out.println(i+" "+a.length);
    foo(i+1);
}

當指定最大堆記憶體50M (-Xmx50M)的時候 遞迴呼叫到40次左右的時候 便會發生記憶體溢位異常

40 1048576
java.lang.OutOfMemoryError: Java heap space

可知遞迴呼叫並未釋放變數a的記憶體佔用

解決
改成迴圈呼叫即可

@Test
public void loopCall(){
    bar();
}

private void bar(){
    int index = 1;
    while (true) {
        byte[] a = new byte[1 * 1024 * 1024];
        System.out.println(index+" "+a.length);
        index ++;
    }
}

同樣設定-Xmx50M 此時可以無限執行下去

相關文章