JVM規范
jvm本身是軟件層級,jvm本身是跑在操作系統的軟件,jvm只是做了一些規范。
jvm層級隊列兩個進行組合,組成了四種屏障,這是jvm虛擬機規定的規范。
LoadLoad屏障
對於這樣的語句Load1;LoadLoad;Load2
在Load2及以后續讀取操作要讀取的數據被訪問前,保證Load1要讀取的數據被讀取完畢
StoreStore屏障
對於這樣的語句Store1;StoreStore;Store2
在Store2及后續寫入操作執行前,保證Store1的寫入操作對其他處理器可見
LoadStore屏障
對於這樣的語句Load1;LoadStore;Store2
在Store2及后續寫入操作被刷出前,保證Load1要讀取的數據被讀取完畢
StoreLoad全能屏障
對於這樣的語句Store1;StoreLoad;Load2
在load2及后續所有讀取操作執行前,保證Store1的寫入對所有處理器可見
volatile的實現細節
字節碼層面(ACC_VOLATILE)
jvm層面
os和硬件層面
JAVA8大原子操作(虛擬機規范)(已棄用)
lock:主內存,標識變量為線程獨占
unlock:主內存,解鎖線程獨占變量
read:主內存,讀取內容到工作內存
load:工作內存,read后的值放入線程本地變量副本
use:工作內存,傳值給執行引擎
assign:工作內存,執行引擎結果賦值給線程本地變量
store:工作內存,存值到主內存給write備用
write:主內存,寫變量值
hanppens-before原則(JVM規定重排序必須遵守的規則)
程序次序規則:同一個線程內,按照代碼出現的順序,前面的代碼先行於后面的代碼,准確的說是控制流順序,因為要考慮到分支和循環結構
管程鎖定規則:一個unlock操作先行發生於后面對同一個鎖的lock操作。
volatile變量規則:對一個volatile變量的寫操作先行發生於后面對這個變量的讀操作。
線程啟動規則:Thread的start()方法先行發生於這個線程的每一個操作
線程終止規則:線程的所有操作都先於此線程的的終止檢測,可以通過Thread.join()方法結束、Thread.isAlive()的返回值等手段檢測線程的終止
線程中斷規則:對線程interrupt()方法的調用先行發生於被中斷線程的代碼檢測到中斷事件的發生,可以通過Thread.interrupt()方法檢測線程是否中斷。
對象終結規則:一個對象的初始化完成先於發生它的finalize()方法的開始。
傳遞性:如果操作A先行於操作B,操作B先行於操作C,那么操作A先行於操作C。
面試題
解釋一下對象的創建過程
比如說我們要創建一個對象new T()第一步肯定是要把classloading到內存->第二步就是linking的過程,包括第三步
1:verification校驗 2:preparation把類的靜態變量設默認值 3:resolution做一個解析->接下來就是類的初始化把靜態變量設為初始值同時執行靜態語句塊。創建對象然后需要申請內存,成員變量再賦默認值,然后調用構造方法在字節碼層面,調用構造方法的時候,把成員變量設為初始值,接下來調用構造方法語句super調用父類。
#對象創建過程
1、class loading
2、class linking(verification,preparation,resolution)
3、class initializing
4、申請對象內存
5、成員變量賦默認值
6、調用構造方法<init>
1、成員變量順序賦初始值
2、執行構造方法語句
對象在內存中的內存布局
作為對象的內存布局來將分為兩種,第一種叫普通對象,第二種叫數組對象
#普通對象首先有
1:第一是對象頭,在hotport里面稱為markword長度是8個字節
2:第二個是ClassPointer指針:-XX:+UseCompressedClassPointers為4個字節不開啟為8個字節
3:第三個是實例數據
1:引用類型:-XX:+UseCompressedOops為四個字節不開啟為八個字節
Oops Ordinary Object Pointers
4:Padding對齊,這個對齊是8的倍數
普通對象樣子,首先有一個對象頭markword8個字節,第二個這個對象它是屬於哪個class的,它有一個指針是ClassPoint指針,這個指針指向你要的class對象,接下來實例數據也就是加成員變量還有引用類型,第四個就是Padding對齊,主要是因為算出來正好是15個字節,但是作為64位機器,它是按塊來讀,不是按你的字節來讀,它這里有一個對齊它是8的倍數。
#數組對象
1、對象頭:markword 8
2、ClassPoint指針同上
3、數組長度:4字節
4、數組數據
5、對齊8的倍數
數組對象多了一項,第一個對象頭一樣,第二個ClassPoint你這個對象數組里裝的是哪種類型的數據,第三個多了一個數組長度4個字節,第四個數組數據,第五個對齊8的倍數。
對象頭具體包括什么
第一鎖定信息兩位代表對象有沒有被鎖定,第二個GC的標記他被回頭多少次了分代年齡
對象怎么定位
對象定位有兩種:1、句柄池 2、直接指針
就是當我們new出來一個對象T t = new T();這個小t是怎么找到對象的,有兩種方式第一種是通過句柄池,通過間接指針,它只第一步把小t指向兩個指針,這兩個指針其中一個指向對象,另一個指向t.class,就是中間隔了一下
第二種直接指向對象然后在指向t.class,他兩沒有優劣之分,有的虛擬機實現用第一種有的用第二種,Hotspot用的是第二種,第二種效率比較高直接找到對象。
對象怎么分配
首先new一個對象的時候先往棧上分配,棧上如果能分配下就分配在棧上,然后棧一彈出對象就沒了,如果棧上分配不下,特別大,直接分配到堆內存,老年代。
如果不大,首先會進行線程本地分配,線程本地分配能分配下就分配,分配不下找伊甸區然后進行GC的過程,GC過程年齡到了就直接到老年代了,如果年齡不到的話GC來GC去一直到年齡到了為止。