什么是指令重排序?為什么要重排序?


 

什么是重排序

假設我們寫了一個 Java 程序,包含一系列的語句,我們會默認期望這些語句的實際運行順序和寫的代碼順序一致。

但實際上,編譯器、JVM 或者 CPU 都有可能出於優化等目的,對於實際指令執行的順序進行調整,這就是重排序。

重排序的好處:提高處理速度

 

 

圖中左側是 3 行 Java 代碼,右側是這 3 行代碼可能被轉化成的指令。可以看出 a = 100 對應的是 Load a、Set to 100、Store a,意味着從主存中讀取 a 的值,然后把值設置為 100,並存儲回去,同理, b = 5 對應的是下面三行  Load b、Set to 5、Store b,最后的 a = a + 10,對應的是 Load a、Set to 110、Store a。如果你仔細觀察,會發現這里有兩次“Load a”和兩次“Store a”,說明存在一定的重排序的優化空間。

 

經過重排序之后,情況如下圖所示:

 

 

重排序后, a 的兩次操作被放到一起,指令執行情況變為 Load a、Set to 100、Set to 110、 Store a。下面和 b 相關的指令不變,仍對應 Load b、 Set to 5、Store b。

可以看出,重排序后 a 的相關指令發生了變化,節省了一次 Load a 和一次 Store a。重排序通過減少執行指令,從而提高整體的運行速度,這就是重排序帶來的優化和好處。

重排序的 3 種情況

下面我們來看一下重排序的 3 種情況。

(1)編譯器優化

編譯器(包括 JVM、JIT 編譯器等)出於優化的目的,例如當前有了數據 a,把對 a 的操作放到一起效率會更高,避免讀取 b 后又返回來重新讀取 a 的時間開銷,此時在編譯的過程中會進行一定程度的重排。不過重排序並不意味着可以任意排序,它需要需要保證重排序后,不改變單線程內的語義,否則如果能任意排序的話,程序早就邏輯混亂了。

 

(2)CPU 重排序

CPU 同樣會有優化行為,這里的優化和編譯器優化類似,都是通過亂序執行的技術來提高整體的執行效率。所以即使之前編譯器不發生重排,CPU 也可能進行重排,我們在開發中,一定要考慮到重排序帶來的后果。

 

(3) 內存的“重排序”

內存系統內不存在真正的重排序,但是內存會帶來看上去和重排序一樣的效果,所以這里的“重排序”打了雙引號。由於內存有緩存的存在,在 JMM 里表現為主存和本地內存,而主存和本地內存的內容可能不一致,所以這也會導致程序表現出亂序的行為。

 

舉個例子,線程 1 修改了 a 的值,但是修改后沒有來得及把新結果寫回主存或者線程 2 沒來得及讀到最新的值,所以線程 2 看不到剛才線程 1 對 a 的修改,此時線程 2 看到的 a 還是等於初始值。但是線程 2 卻可能看到線程 1 修改 a 之后的代碼執行效果,表面上看起來像是發生了重順序。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM