1. 程式人生 > >關於JVM的逃逸分析

關於JVM的逃逸分析

pub 中一 學習 stringbu art 全局 但是 新的 可能

何謂“逃逸”?

  我們都知道Java中的對象默認是分配到堆上的,垃圾回收機制也會回收堆中不再使用的對象,但在此之前需要篩選可回收的對象,因此會造成,回收對象還有整理內存,都比較耗時間,開銷也是非常之大。而此也是Java語言被瘋狂吐槽的一地方,就是Java不支持棧上分配對象。而在我們日常開發中,內存,時間都是相當的寶貴,如何優化成為在開發中一個不可或缺的環節。

  逃逸分析(Escape Analysis),是一種可以有效減少Java 程序中同步負載和內存堆分配壓力的跨函數全局數據流分析算法。通過逃逸分析,Java Hotspot編譯器能夠分析出一個新的對象的引用的使用範圍從而決定是否要將這個對象分配到堆上。

逃逸分析算是目前Java虛擬機中比較前沿的優化技術了,但至於適不適合,需要據實際情況而定了。

  在計算機語言編譯器優化原理中,逃逸分析是指分析指針動態範圍的方法,它同編譯器優化原理的指針分析和外形分析相關聯。當變量(或者對象)在方法中分配後,其指針有可能被返回或者被全局引用,這樣就會被其他方法或者線程所引用,這種現象稱作指針(或者引用)的逃逸(Escape)。通俗點講,如果一個對象的指針被多個方法或者線程引用時,那麽我們就稱這個對象的指針發生了逃逸。

  網上有位博友這麽形容逃逸分析,用了一段簡單直接的代碼,請看:

public StringBuilder escapeDemo1(System a, System b) {
    StringBuilder stringBuilder 
= new StringBuilder(); stringBuilder.append(a); stringBuilder.append(b); return stringBuilder; }

  StringBuilder是方法的一個內部變量,而此時將它直接返回,這樣StringBuilder就有可能被其他地方的方法或變量改變,這樣它的作用域就不只是demo1方法了,雖然它是一個局部變量,但其發生了“逃逸事故”。

  那麽,我可以改一下代碼:

public String escapeDemo2(System a, System b) {

    StringBuilder stringBuilder 
= new StringBuilder(); stringBuilder.append(a); stringBuilder.append(b); return stringBuilder.toString(); }

  如此再沒有返回StringBuilder,而是toString(),那麽StringBuilder沒有從方法中脫離,將不會發生逃逸。

  換種方式理解吧,因為Java本身的限制(對象只能分配到堆中),我可以這麽操作了,為了減少臨時對象在堆內分配的數量,我會在一個方法體內定義一個局部變量,並且該變量在方法執行過程中未發生逃逸,按照JVM調優機制,首先會在堆內存創建類的實例,然後將此對象的引用壓入調用棧,繼續執行,這是JVM優化前的方式。然後,我采用逃逸分析對JVM進行優化。即針對棧的重新分配方式,首先找出未逃逸的變量,將該變量直接存到棧裏,無需進入堆,分配完成後,繼續調用棧內執行,最後線程執行結束,棧空間被回收,局部變量也被回收了。如此操作,是優化前在堆中,優化後在棧中,從而減少了堆中對象的分配和銷毀,從而優化性能。

  但是逃逸分析會有時間消耗,所以性能不一定會有提升,並且由於逃逸分析比較耗時,目前的實現都是采用不那麽準確但是時間壓力相對較小的算法來完成逃逸分析,這就有可能導致效果不穩定,所以,要根據實際情況,酌情處理。

  一項技術的好壞,不是憑嘴說說,適合自己的才是最好的。

  ok,純屬結合項目實際,整理前人文言,權當學習手劄。

你有興趣,推薦你以下好文:

淺談HotSpot逃逸分析

Java 逃逸分析

https://dzone.com/articles/escape-analysis-java-6-update

關於JVM的逃逸分析