JVM系列【4】記憶體模型

JVM系列筆記目錄

  • 虛擬機的基礎概念
  • class文件結構
  • class文件載入過程
  • jvm記憶體模型
  • JVM常用指令
  • GC與調優

硬體層數據一致性

– 存儲器層次結構

file

從L6-L0 空間由大變小,速度由慢到快。

-快取一致性演算法

CPU實現快取一致性的協議很多,其中intel 使用的MESI(Modified Exclusive Shared Or Invalid)協議。具體可以參考:[MESI–CPU快取一致性協議](//www.cnblogs.com/z00377750/p/9180644.html)

file

現代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_VOLATILE

  • JVM層面

    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位元組和具體的數組數據。

file

  • 3.對象頭具體包括什麼

    對象頭markword(8位元組)具體內容和對象鎖狀態有關係,其中最高位2位是鎖狀態中,最低3位用作鎖標誌位,中間4位是GC年齡,如下。

  • 4.對象怎麼定位

    通過句柄池和直接指針,具體參考:訪問對象兩種方式–句柄和直接指針

  • 5.對象怎麼分配?

    對象的分配其實和垃圾回收GC有關係,後續總結GC詳細講。

file

  • 6.Object o = new Object() 在記憶體中的佔用多少個位元組

    16個位元組,根據第2點的記憶體布局可以算出。

知識分享,轉載請註明出處。學無先後,達者為先!

Tags: