搜尋
首頁Javajava教程如何理解Java中的逃逸

在Java的編譯體系中,一個Java的原始碼檔案變成電腦執行的機器指令的過程中,需要經過兩段編譯,第一段是把.java檔轉換成.class檔。第二段編譯是把.class轉換成機器指令的過程。

第一段編譯就是javac指令。

在第二編譯階段,JVM 透過解釋字節碼將其翻譯成對應的機器指令,逐條讀入,逐條解釋翻譯。很顯然,經過解釋執行,其執行速度必然會比可執行的二進位字節碼程式慢很多。這就是傳統的JVM的解譯器(Interpreter)的功能。為了解決這種效率問題,引入了 JIT(即時編譯) 技術。

在引入了 JIT 技術後,Java程式還是透過解釋器進行解釋執行,當JVM發現某個方法或程式碼區塊運作特別頻繁的時候,就會認為這是「熱點程式碼」(Hot Spot Code)。然後JIT會把部分「熱點代碼」翻譯成本地機器相關的機器碼,並進行優化,然後再把翻譯後的機器碼緩存起來,以備下次使用。

由於關於JIT編譯和熱點檢測的內容,我在深入分析Java的編譯原理中已經介紹過了,這裡就不在贅述,本文主要來介紹下JIT中的最佳化。 JIT優化中最重要的一個就是逃逸分析。

逃逸分析

關於逃逸分析的概念,可以參考物件和陣列並不是都在堆上分配記憶體的。一文,這裡簡單回顧一下:

# 逃逸分析的基本行為是分析物件動態作用域:當一個物件在方法中被定義後,它可能被外部方法所引用,例如作為呼叫參數傳遞到其他地方中,稱為方法逃逸。

例如以下程式碼:

public static StringBuffer craeteStringBuffer(String s1, String s2) {

#     StringBuffer sb = new StringBuffer();

    sb.append(s1);

#     sb.append(s2);

#     return sb;

}

public static String createStringBuffer(String s1, String s2) {

#     StringBuffer sb = new StringBuffer();

    sb.append(s1);

#     sb.append(s2);

#     return sb.toString();

# }

第一段程式碼中的sb就逃逸了,而第二段程式碼中的sb就沒有逃逸。

使用逃逸分析,編譯器可以對程式碼做如下最佳化:

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

二、將堆分配轉換為棧分配。如果一個物件在子程式中被分配,要使指向該物件的指標永遠不會逃逸,物件可能是堆疊分配的候選,而不是堆疊分配。

三、分離對像或標量替換。有的物件可能不需要作為一個連續的記憶體結構存在也可以被存取到,那麼物件的部分(或全部)可以不儲存在內存,而是儲存在CPU暫存器中。

在Java程式碼執行時,透過JVM參數可指定是否開啟逃逸分析,

# -XX: DoEscapeAnalysis : 表示開啟逃逸分析

-XX:-DoEscapeAnalysis : 表示關閉逃逸分析 從jdk 1.7開始已經預設開始逃逸分析,如需關閉,需要指定-XX:-DoEscapeAnalysis

同步省略

# 在動態編譯同步區塊的時候,JIT編譯器可以藉助逃逸分析來判斷同步區塊所使用的鎖定物件是否只能夠被一個執行緒存取而沒有被發佈到其他執行緒。

如果同步區塊所使用的鎖定物件透過這種分析被證實只能夠被一個執行緒訪問,那麼JIT編譯器在編譯這個同步區塊的時候就會取消對這部分程式碼的同步。這個取消同步的過程就叫同步省略,也叫鎖消除。

如以下程式碼:

public void f() {

    Object hollis = new Object();

#     synchronized(hollis) {

#         System.out.println(hollis);

    }

}

程式碼中對hollis這個物件進行加鎖,但是hollis物件的生命週期只在f()方法中,並不會被其他執行緒所存取到,所以在JIT編譯階段就會被最佳化掉。優化成:

public void f() {

    Object hollis = new Object();

#     System.out.println(hollis);

# }

所以,在使用synchronized的時候,如果JIT經過逃逸分析之後發現並無線程安全問題的話,就會做鎖定消除。

標量替換

標量(Scalar)是指一個無法再分解成更小的資料的資料。 Java中的原始資料型別就是標量。相對的,那些還可以分解的資料叫做聚合量(Aggregate),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.x "; point.y=" point.y);

}

class Point{

    private int x;

    private int y;

}

以上程式碼中,point物件並沒有逃逸出alloc方法,且point物件是可以拆解成標量的。那麼,JIT就會不會直接建立Point對象,而是直接使用兩個標量int x ,int y來取代Point對象。

以上程式碼,經過標量替換後,就會變成:

private static void alloc() {

   int x = 1;

   int y = 2;

   System.out.println("point.x=" x "; point.y=" y);

}

可以看到,Point這個聚合量經過逃逸分析後,發現他並沒有逃逸,就被替換成兩個聚合量了。那麼標量替換有什麼好處呢?就是可以大大減少堆記憶體的佔用。因為一旦不需要建立物件了,那就不再需要分配堆記憶體了。

標量替換為堆疊上分配提供了很好的基礎。

堆疊上分配

在Java虛擬機器中,物件是在Java堆中分配記憶體的,這是一個普遍的常識。但是,有一種特殊情況,那就是如果經過逃逸分析後發現,一個物件並沒有逃逸出方法的話,那麼就可能被優化成棧上分配。這樣就無需在堆上分配內存,也無須進行垃圾回收了。

關於堆疊上分配的詳細介紹,可以參考物件和陣列並不是都在堆上分配記憶體的。 。

這裡,還是要簡單說一下,其實在現有的虛擬機器中,並沒有真正的實作棧上分配,在物件和陣列並不是都在堆上分配記憶體的。在中我們的例子中,物件沒有在堆上分配,其實是標量替換實現的。

逃逸分析並不成熟

關於逃逸分析的論文在1999年就已經發表了,但直到JDK 1.6才有實現,而且這項技術到如今也並不是十分成熟的。

根本原因就是無法保證逃逸分析的效能消耗一定能高於他的消耗。雖然經過逃逸分析可以做標量替換、棧上分配、和鎖消除。但是逃逸分析本身也是需要進行一連串複雜的分析的,這其實也是一個相對耗時的過程。

一個極端的例子,就是經過逃逸分析之後,發現沒有一個物體是不逃逸的。那這個逃逸分析的過程就白白浪費掉了。

雖然這項技術並不十分成熟,但他也是即時編譯器優化技術中十分重要的手段。

以上是如何理解Java中的逃逸的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:亿速云。如有侵權,請聯絡admin@php.cn刪除
如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?Mar 17, 2025 pm 05:46 PM

本文討論了使用Maven和Gradle進行Java項目管理,構建自動化和依賴性解決方案,以比較其方法和優化策略。

如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?Mar 17, 2025 pm 05:45 PM

本文使用Maven和Gradle之類的工具討論了具有適當的版本控制和依賴關係管理的自定義Java庫(JAR文件)的創建和使用。

如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?Mar 17, 2025 pm 05:44 PM

本文討論了使用咖啡因和Guava緩存在Java中實施多層緩存以提高應用程序性能。它涵蓋設置,集成和績效優勢,以及配置和驅逐政策管理最佳PRA

如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?Mar 17, 2025 pm 05:43 PM

本文討論了使用JPA進行對象相關映射,並具有高級功能,例如緩存和懶惰加載。它涵蓋了設置,實體映射和優化性能的最佳實踐,同時突出潛在的陷阱。[159個字符]

Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Mar 17, 2025 pm 05:35 PM

Java的類上載涉及使用帶有引導,擴展程序和應用程序類負載器的分層系統加載,鏈接和初始化類。父代授權模型確保首先加載核心類別,從而影響自定義類LOA

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它們
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具