JVM系列【4】記憶體模型
JVM系列筆記目錄
- 虛擬機的基礎概念
- class文件結構
- class文件載入過程
- jvm記憶體模型
- JVM常用指令
- GC與調優
硬體層數據一致性
– 存儲器層次結構
從L6-L0 空間由大變小,速度由慢到快。
-快取一致性演算法
CPU實現快取一致性的協議很多,其中intel 使用的MESI(Modified Exclusive Shared Or Invalid)協議。具體可以參考:[MESI–CPU快取一致性協議](//www.cnblogs.com/z00377750/p/9180644.html)
現代CPU的數據一致性實現=快取鎖(MESI…) +匯流排鎖
-快取行
快取讀取時的單位,一般是64Byte
使用快取行的對齊能夠提高效率
-偽共享
位於同一快取行的2個不同的數據,被2個不同的CPU鎖定,產生互相影響的偽共享問題。
如何解決? 使用快取行的對齊能夠提高效率
CPU亂序問題
– 概念
CPU為了提高執行效率,會在一條指令執行的過程中(比如去記憶體取數據(慢100倍)),去同時執行另一條指令,前提是兩條指令沒有依賴關係。具體參考:[現代cpu的合併寫技術對程式的影響](//www.cnblogs.com/liushaodong/p/4777308.html)
-合併寫
CPU上有一個WriteCombinBuffer,僅4個位元組,比L1等級還高,某些寫操作會合併在一起提交。[現代cpu的合併寫技術對程式的影響](//www.cnblogs.com/liushaodong/p/4777308.html)
-亂序證明
CPU亂序現象有大佬寫程式模擬出來了,具體參考: Memory Reordering Caught in the Act
如何保證在特定情況下保證不亂序
硬體級別
X86 CPU級別記憶體屏障
sfence
store fence 在sfence指令前的寫操作必須在sfence指令後的寫操作前完成lfence
load fence 在lfence指令前的讀操作必須在lfence指令後的讀操作前完成mfence
mixed fence 在mfence指令前的讀寫操作必須在mfence指令後的讀寫操作前完成CPU原子指令
如x86上的」lock …」 指令是一個Full Barrier,執行時會鎖住記憶體子系統來確保執行順序,甚至跨多個CPU總結: Software Locks通常使用了記憶體屏障或原子指令來實現變數可見性和保持程式順序
JVM級別
JSR113規範規定了4種記憶體屏障
LoadLoad屏障
對於語句Load1;LoadLoad;Load2,在Load2及後續讀取指令要讀取的數據被訪問前,保證Load1要讀取的數據被讀取完畢StoreStore屏障
對於語句Store1;StoreStore;Store2,在Store2及後續寫操作執行前,保證Store1的寫入操作對其它處理器可見LoadStore屏障
對於語句Load1;StoreStore;Store2,在Store2及後續寫操作被刷出前,保證Load1要讀取的數據被讀取完畢StoreLoad屏障
對於語句Store1;StoreStore;Load2,在Load2及後續讀取指令要執行前,保證Store1的寫入操作對其它處理器可見
sychronized/volatile在位元組碼、JVM、硬體OS層面實現細節
– sychronized
位元組碼層面
sychronized m() : AccessFlag : ACC_VOLATILE
sychronized(this){} : monitorenter monitorexit monitorenter
JVM層面
C/C++ 調用作業系統的同步操作
硬體OS層面
X86 : lock cmpxchg / xxx
-volatile
位元組碼層面
AccessFlag : ACC_VOLATILEJVM層面
volatile記憶體區域都加屏障
StoreStoreBarrier volatile 寫操作 StoreLoadBarrier
LoadLoadBarrier volatile 讀操作 LoadStoreBarrier
硬體OS層面
windows lock 指令實現 或是 MESI實現
面試new Object() 6連問
-
1.解釋對象的創建過程
該問題結合上篇部落格:JVM系列【3】Class文件載入過程不難回答出來。
class loading
class linking (vertification prepraration resolution)
class initiazing
new 申請記憶體空間
成員變數賦初始值
調用構造方法
:成員變數賦初始值;執行構造方法語句,super()父類構造。 -
2.對象在記憶體中的存儲布局
對象在記憶體中布局分普通對象和數組對象。
普通對象4部分:對象頭markword(8位元組)、ClassPointer指針(4或8位元組)、實例數據、padding對齊為8的倍數。
數組對象5部分,和普通對象類似,但中間是數組長度4位元組和具體的數組數據。
-
3.對象頭具體包括什麼
對象頭markword(8位元組)具體內容和對象鎖狀態有關係,其中最高位2位是鎖狀態中,最低3位用作鎖標誌位,中間4位是GC年齡,如下。
-
4.對象怎麼定位
通過句柄池和直接指針,具體參考:訪問對象兩種方式–句柄和直接指針
-
5.對象怎麼分配?
對象的分配其實和垃圾回收GC有關係,後續總結GC詳細講。
-
6.Object o = new Object() 在記憶體中的佔用多少個位元組
16個位元組,根據第2點的記憶體布局可以算出。
知識分享,轉載請註明出處。學無先後,達者為先!