1. 程式人生 > 實用技巧 >說說逃逸分析和棧上分配

說說逃逸分析和棧上分配

說說逃逸分析和棧上分配

  • 逃逸分析:

    • 它是可以有效減少java程式中同步負載和記憶體堆分配壓力的跨函式全域性資料流分析演算法。它能夠分析出一個新的物件的引用的使用範圍從而決定是否要將這個物件分配到堆上。

    • 當一個物件在方法中被定義後,物件只在方法內部使用,則認為沒有發生逃逸。

    • 當一個物件在方法中被定義後,它被外部方法所引用,則認為發生逃逸。例如作為呼叫引數傳遞到其他地方。

    • 什麼情況下認為逃逸:

       /*
          物件的作用域僅在當前方法中有效,沒有發生逃逸
           */
          public void useEscapeAnalysis(){
              EscapeAnalysis e = new EscapeAnalysis();
          }
      
          public static String createStringBuffer(String s1,String s2){
              StringBuffer sb = new StringBuffer();
              sb.append(s1);
              sb.append(s2);
              return sb.toString();
          }
      
  1. 什麼是棧上分配?

棧上分配主要是指在Java程式的執行過程中,在方法體中宣告的變數以及建立的物件,將直接從該執行緒所使用的棧中分配空間。 一般而言,建立物件都是從堆中來分配的,這裡是指在棧上來分配空間給新建立的物件。

  • 逃逸分析的作用:

    • 棧上分配:將堆分配轉化為棧分配。如果一個物件在子程式中被分配,要是指向該物件的指標不會逃逸,物件可能是棧分配的候選。

    • 同步省略:如果一個物件被發現只能從一個執行緒被訪問到,那麼對於這個物件的操作可以考慮不同步。

      • 執行緒同步的代價是相當高的,同步的後果是降低併發性和效能。
      • 在動態編譯同步塊的時候,JIT編譯器可以藉助逃逸分析來判斷同步塊所使用的鎖物件是否只能被一個執行緒訪問而沒有釋出到其他執行緒。如果沒有,則可以取消這部分程式碼的同步,也叫鎖消除。
      public void f(){
          Object hollis = new Object();
          synchronized(hollis){
              System.out.println(hollis);
          }
      }
      
      /**
      * 優化成下方的
      */
      public void f(){
          Object hollis = new Object();
              System.out.println(hollis);
      }
      
      
    • 標量替換:有的物件可能不需要作為一個連續的記憶體結構存在也可以被訪問到,那麼物件的部分可以不儲存在記憶體,而且存在CPU暫存器中。

      • 標量是指一個無法再分解成更小的資料的資料。Java中的原始資料型別就是標量。在JIT階段,如果經歷逃逸分析,發現一個物件不會被外界訪問的話,那麼經過JIT優化,就會把這個物件拆解成若干個其中包含的若干個成員變數來代替。這個過程就是標量替換。
      public static void main(String[] args){
          alloc();
      }
      private static void alloc(){
          Point point = new Point(1,2);
          System.out.println(point.x+point.y);
      }
      class Point{
          private int x;
          private int y;
      }
      
      /**
      *替換成下面這種
      */
      private static void alloc(){
          int x = 1;
          int y = 2;
          System.out.println(x+y);
      }
      
      
    • 可以看到,Point這個聚合量經過逃逸分析後,發現他沒有逃逸,就被換成2個聚合量,就可以減少堆記憶體的佔用。因為一旦不需要建立物件,那麼就不再需要分配堆記憶體了。