逃逸分析:分離物件、標量替換、同步鎖消除

碼農談IT發表於2024-01-17


來源:冰河技術

在JVM的實現中,為了提高JVM的效能和節省記憶體空間,JVM提供了一種叫做“逃逸分析”的特性,而且對於“逃逸分析”這種特性,也是近年來大廠面試常問的知識點。今天,我們就一起來聊聊什麼是逃逸分析。

逃逸分析的概念

先以官方的形式來說下什麼是逃逸分析。逃逸分析就是:一種確定指標動態範圍的靜態分析,它可以分析在程式的哪些地方可以訪問到指標。

在JVM的即時編譯語境下,逃逸分析將判斷新建的物件是否逃逸。即時編譯判斷物件是否逃逸的依據:一種是物件是否被存入堆中(靜態欄位或者堆中物件的例項欄位),另一種就是物件是否被傳入未知程式碼。

直接說這些概念,確實有點暈啊,那我們就來兩個示例。

物件逃逸示例

一種典型的物件逃逸就是:物件被複制給成員變數或者靜態變數,可能被外部使用,此時變數就發生了逃逸。

我們可以用下面的程式碼來表示這個現象。

/**
 * @author binghe
 * @description 物件逃逸示例1
 */

public class ObjectEscape{
    private User user;
    public void init(){
        user = new User();
    }
}

在ObjectEscape類中,存在一個成員變數user,我們在init()方法中,建立了一個User類的物件,並將其賦值給成員變數user。此時,物件被複制給了成員變數,可能被外部使用,此時的變數就發生了逃逸。

另一種典型的場景就是:物件透過return語句返回。如果物件透過return語句返回了,此時的程式並不能確定這個物件後續會不會被使用,外部的執行緒可以訪問到這個變數,此時物件也發生了逃逸。

我們可以用下面的程式碼來表示這個現象。

/**
 * @author binghe
 * @description 物件逃逸示例2
 */

public class ObjectReturn{
    public User createUser(){
        User user = new User();
        return user;
    }
}

給出兩個示例,相信小夥伴們對JVM的逃逸分析多少有點了解了吧,沒錯,JVM透過逃逸分析,能夠分析出新物件的使用範圍,從而決定新物件是否要在堆上進行分配。

還沒完,我們繼續看下逃逸分析的優點,以便於小夥伴們能夠更好的理解逃逸分析。

逃逸分析的優點

逃逸分析的優點總體上來說可以分為三個:物件可能分配在棧上、分離物件或標量替換、消除同步鎖。我們可以使用下圖來表示。

逃逸分析:分離物件、標量替換、同步鎖消除

物件可能分配在棧上

JVM透過逃逸分析,分析出新物件的使用範圍,就可能將物件在棧上進行分配。棧分配可以快速地在棧幀上建立和銷燬物件,不用再將物件分配到堆空間,可以有效地減少 JVM 垃圾回收的壓力。

分離物件或標量替換

當JVM透過逃逸分析,確定要將物件分配到棧上時,即時編譯可以將物件打散,將物件替換為一個個很小的區域性變數,我們將這個打散的過程叫做標量替換。將物件替換為一個個區域性變數後,就可以非常方便的在棧上進行分配了。

同步鎖消除

如果JVM透過逃逸分析,發現一個物件只能從一個執行緒被訪問到,則訪問這個物件時,可以不加同步鎖。如果程式中使用了synchronized鎖,則JVM會將synchronized鎖消除。

這裡,需要注意的是:這種情況針對的是synchronized鎖,而對於Lock鎖,則JVM並不能消除。

要開啟同步消除,需要加上 -XX:+EliminateLocks 引數。因為這個引數依賴逃逸分析,所以同時要開啟 -XX:+DoEscapeAnalysis 選項。

所以,並不是所有的物件和陣列,都是在堆上進行分配的,由於即時編譯的存在,如果JVM發現某些物件沒有逃逸出方法,就很有可能被最佳化成在棧上分配。

衍生出的面試題

其實,針對逃逸分析還會衍生出一些典型的面試題,例如:Java中的物件一定是在堆上分配的嗎? 只要我們充分掌握了逃逸分析的原理,回答這種面試題就非常簡單了。

關於面試題

Java中的物件一定是在堆上分配的嗎?

面試官這樣問,如果大家不瞭解逃逸分析的話,那肯定就有些小夥伴心裡會想:我從一開始學習Java時,就知道了:Java中的物件是在堆上建立的,物件的引用是儲存到棧中的,那Java中的物件是在堆上分配的啊!難道不是嗎?

如果你這樣回答,就會被直接Pass掉。

今天,我們介紹完什麼是逃逸分析後,相信各位小夥伴就知道如何去完美的回答這道面試題了吧。

面試題解答思路

總體思路上,你可以這樣回答:Java中的物件不一定是在堆上分配的,因為JVM透過逃逸分析,能夠分析出一個新物件的使用範圍,並以此確定是否要將這個物件分配到堆上。



來自 “ ITPUB部落格 ” ,連結:https://blog.itpub.net/70024924/viewspace-3004151/,如需轉載,請註明出處,否則將追究法律責任。

相關文章