小小面試一下
前言蜜語
最近馬師傅火的不要不要的,雖然沒有搶到耗子尾汁的商標註冊權,可是必須得蹭一波馬師傅的熱度,下面就是閃電五連鞭的教學環節,你準備好了嗎!java
在正式內容開始前先甩兩篇關於類加載機制和內存佈局的文章,由於今天的內容多少與這兩篇文章有直接的聯繫,對這方面還比較薄弱的朋友能夠先看看,地址我放在下面。面試
今天本文的內容就針對剛剛模擬面試兩個問題jvm
1.對象的建立過程佈局
2.對象的內存佈局學習
對象的建立過程
如下內容基於HotSpot VM 分代模型線程
這張圖其實就能完整的說明一個對象的建立過程到底發生了什麼,不少朋友可能一下看不懂,那麼咱們就跟着左上角的一步一步來:指針
-
一個對象new出來先判斷線程棧是否能分配下對象
- 若是能分配下,直接分配在棧中。
- 若是分配不下則進行第二步。
-
判斷該對象是否足夠大
- 若是足夠大,則直接進入老年代。
- 若是不夠大,則進行第三步。
-
判斷建立對象的線程的TLAB(本地線程緩衝區)空間是否足夠
- 若是足夠,直接分配在TLAB中。
- 若是不夠,則進入Eden區中其餘空間。而後進行第四步。
-
GC清除
- 若是清除掉了該對象,則直接結束。
- 若是沒有清除掉對象,進行第5步。
-
此刻對象進入Survivor 1 區,判斷年齡是否足夠大
- 若是年齡足夠大,則直接進入old區域。
- 若是年齡不夠大,則進入Survivor 2 區,而後進入第4步,循環往復。
經過這張流程圖和步驟解析你們應該對一個對象的建立過程有一個很清晰的概念了,可是其中仍是有不少小細節會被忽略,爲何jvm會在對象的建立過程當中大做文章,會分這麼多種狀況?爲了讓你們更深刻的可以理解它,咱們就再來看看下面這幾個問題:
- 爲何對象會選擇先分配在棧中?
首先棧是線程私有的,將對象優先分配在棧中,能夠經過pop直接將對象的全部信息,空間直接清除,當線程消亡的時候也能夠直接清理這一起TLAB區域。
- 爲何jvm會讓大對象會直接進入老年代?
大對象須要連續的空間來存儲,若是不存入老年代對jvm說就多是一個負擔,若是沒有足夠的空間就有可能致使提早觸發gc來清理空間來安置大對象。
- 爲何會選擇先進入TLAB?
TLAB是線程本地緩衝區,TLAB的好處就是防止不一樣線程建立對象選擇同一起內存區域而產生競爭,會使其機率大大減小。
- 爲何會有兩個Survivor區?而且存活且年齡不夠大的對象會從一個Survivor區轉到另外一個Survivor區?
根據根可達算法,jvm會從開始尋找到全部正在使用的對象,沒有使用的就是垃圾,一般狀況下,不少對象都是用完就拋棄的,因此真正在Survivor區長時間存活的對象很是少,將這部分對象從一個Survivor區轉到另外一個Survivor區後,就能夠直接對這個Survivor區進行全量的空間回收了,效率會很高。
對象的內存佈局
做者可不是標題黨,哈哈,因此咱們回到文章的標題,Object o = new Object();到底佔用多少個字節?這道題的目的其實就是考驗看你對對象的內存佈局瞭解的是否清晰,先上圖:
在java中對象的內存佈局分爲兩種狀況,非數組對象和數組對象,數組對象和非數組對象的區別就是須要額外的空間存儲數組的長度length。
對象頭
對象頭又分爲MarkWord和Class Pointer兩部分。
-
MarkWord:包含一系列的標記位,好比輕量級鎖的標記位,偏向鎖標記位,gc記錄信息等等,在32位系統佔4字節,在64位系統中佔8字節。
-
ClassPointer:用來指向對象對應的Class對象(其對應的元數據對象)的內存地址。在32位系統佔4字節,在64位系統中佔8字節。
-
Length:只在數組對象中存在,用來記錄數組的長度,佔用4字節
Interface data
- Interface data:對象實際數據,對象實際數據包括了對象的全部成員變量,其大小由各個成員變量的大小決定。(這裏不包括靜態成員變量,由於其是在方法區維護的)
Padding
- Padding:Java對象佔用空間是8字節對齊的,即全部Java對象佔用bytes數必須是8的倍數,是由於當咱們從磁盤中取一個數據時,不會說我想取一個字節就是一個字節,都是按照一起一起來取的,這一塊大小是8個字節,因此爲了完整,padding的做用就是補充字節,保證對象是8字節的整數倍。
moon在上文特地標註了32位系統和64位系統不一樣區域佔用空間大小的區別,這是由於對象指針在64位JVM下的尋址更長,因此想比32位會多出來更多佔用空間。
可是如今假設一個場景,公司如今項目部署的機器是32位的,大家老闆要讓你將項目遷移到64位的系統上,可是又由於64位系統比32位系統要多出更多佔用空間,怎麼辦,由於正常來講咱們是不須要這一部分多餘空間的,因此jvm已經幫你考慮好了,那就是指針壓縮。
指針壓縮
-XX:+UseCompressedOops 這個參數就是JVM提供給你的解決方案,能夠壓縮指針,將佔用的空間壓縮爲原來的一半,起到節約空間的做用,classpointer參數大小就受到其影響。
Object o = new Object()到底佔用多少個字節?
經過剛纔內存佈局的學習後,這個問題就很好回答了,面試官其實就是想問你對象的內存佈局是怎樣的,咱們這裏就針對這個問題的結果分析下,這裏分兩種狀況:
-
在開啓指針壓縮的狀況下,markword佔用4字節,classpoint佔用8字節,Interface data無數據,總共是12字節,因爲對象須要爲8的整數倍,Padding會補充4個字節,總共佔用16字節的存儲空間。
-
在沒有指針的狀況下,markword佔用8字節,classpoint佔用8字節,Interface data無數據,總共是16字節。
結語
今天的文章和你們介紹了一個對象的建立過程,從它的出生到死亡,都經歷了什麼?也和你們詳細的說明了對象的內存佈局,深刻解剖了一下對象的身體構造,這下面試官再問你,可就有的聊了,這篇文章的內容仍是比較肝的,須要你們認真閱讀一下,固然,也能夠關注個人公衆號'moon聊技術',私下聯繫我,我是moon,下期見~