1. 程式人生 > 實用技巧 >java堆是分配物件的唯一選擇嗎

java堆是分配物件的唯一選擇嗎

在《深入理解Java虛擬機器》中關於Java堆記憶體有這樣一段描述:

  隨著JIT編譯期的發展與逃逸分析技術逐漸成熟,棧上分配、標量替換優化技術將會導致一些微妙的變化,所有的物件都分配到堆上也漸漸變得不那麼“絕對”了。
  在Java虛擬機器中,物件是在Java堆中分配記憶體的,這是一個普遍的常識。但是,有一種特殊情況,那就是如果經過逃逸分析(Escape Analysis)後發現,一個物件並沒有逃逸出方法的話,那麼就可能被優化成棧上分配。這樣就無需在堆上分配記憶體,也無須進行垃圾回收了。這也是最常見的堆外儲存技術。
  此外,前面提到的基於openJDK深度定製的TaoBaoVM,其中創新的GCIH (Gcinvisible heap)技術實現off-heap,將生命週期較長的Java物件從heap中移至heap外,並且Gc不能管理GCIH內部的Java物件,以此達到降低Gc的回收頻率和提升GC的回收效率的目的。

逃逸分析:判斷是否逃逸依據看物件是否會被外部所呼叫

  將堆上的物件分配到棧,需要便用逃逸分析手段。
  這是一種可以有效減少Java程式中同步負載和記憶體堆分配壓力的跨函式全域性資料流分析演算法。
  通過逃逸分析,Java Hotspot編譯器能夠分析出一個新的物件的引用的使用範圍從而決定是否要將這個物件分配到堆上。
  逃逸分析的基本行為就是分析物件動態作用域:
    當一個物件在方法中被定義後,物件只在方法內部使用,則認為沒有發生逃逸。
    當一個物件在方法中被定義後,它被外部方法所引用,則認為發生逃逸。例如作為呼叫引數傳遞到其他地方中。

例1:

物件A沒有發生逃逸,直接在棧上分配,隨著方法執行的結束,棧空間被移除;

public void myMethod(){
        A a =new A();
        ...
        a = null;
    }

例2:

    //StringBuilder 逃逸
    public static StringBuilder getSb(String a ,String b){
        StringBuilder sb =new StringBuilder();
        sb.append(a);
        sb.append(b);
        return sb;
    }
    //StringBuilder 沒有逃逸
public static String getSbStr(String a ,String b){ StringBuilder sb =new StringBuilder(); sb.append(a); sb.append(b); return sb.toString(); }

結論:

  開發中能使用區域性變數的,就不要在方法外定義;