JVM的逃逸分析

對象必定分配在堆中嗎?java

JVM經過逃逸分析,那些逃不出方法的對象會在棧上分配。優化

什麼是逃逸分析?線程

EscapeAnalysis,逃逸分析,指的是虛擬機在運行期經過計算分析將本來在堆上分配的對象改爲在棧中分配,這樣的好處是棧上分配的對象隨着線程的結束而自動銷燬,不依賴於GC,能夠下降垃圾收集器運行的頻率。code

如何斷定爲逃逸?對象

JVM判斷新建立的對象是否逃逸的依據有兩個:內存

  1. 對象被賦值給堆中對象的字段和類的靜態變量
  2. 對象被傳進了不肯定的代碼中去運行

若是知足了以上狀況的任意一種,那這個對象JVM就會斷定爲逃逸,對以上兩種狀況舉例,樣例來源於:https://zhuanlan.zhihu.com/p/59215831get

public class EscapeTest {

    public static Object globalVariableObject;

    public Object instanceObject;

    public void globalVariableEscape(){
        globalVariableObject = new Object(); // 靜態變量,外部線程可見,發生逃逸
    }

    public void instanceObjectEscape(){
        instanceObject = new Object(); // 賦值給堆中實例字段,外部線程可見,發生逃逸
    }
    
    public Object returnObjectEscape(){
        return new Object();  // 返回實例,外部線程可見,發生逃逸
    }

    public void noEscape(){
        Object noEscape = new Object();  // 僅建立線程可見,對象無逃逸
    }

}

Java的逃逸分析只能發生在即時編譯(JIT)期,爲何不能在靜態編譯(javac)中?同步

參考R大回答:https://www.zhihu.com/questio...虛擬機

總結來講是能夠發生在靜態編譯期的,可是Java的分離編譯和動態加載使得前期的靜態編譯的逃逸分析比較困難或收益較少,因此目前Java的逃逸分析只發在JIT的即時編譯中,由於收集到足夠的運行數據JVM能夠更好的判斷對象是否發生了逃逸。io

JVM開啓逃逸分析之後的優點?

Java8+默認是開啓的, -XX:+DoEscapeAnalysis
  1. 棧上分配,虛擬機參數:-XX:+PrintGC -Xms5M -Xmn5M -XX:+DoEscapeAnalysis

    • 這種優化能夠下降垃圾收集器運行的頻率,這樣每當方法出棧,對象內存隨之釋放。

      public static void main(String[] args) {
          for(int i = 0; i < 5000000; i++) {
              createObject();
          }
      }
      
      public static void createObject() {
          new Object();
      }
  2. 同步消除

    • 若是發現某個對象只能從一個線程可訪問,那麼在這個對象上的操做能夠不須要同步。
  3. 標量替換

    • 若是某個對象的訪問方式不要求該對象是一個連續的內存結構,那麼對象的部分(或所有)能夠不存儲在內存,而是存儲在CPU寄存器中。簡單來講就是把對象分解成一個個基本類型,而且內存分配再也不是分配在堆上,而是分配在棧上。這樣的好處有,1、減小內存使用,由於不用生成對象頭。 2、程序內存回收效率高,而且GC頻率也會減小。
相關文章
相關標籤/搜索