面試官問我:Object o = new Object() 占用了多少個字節?


小小面試一下

前言蜜語

   最近馬師傅火的不要不要的,雖然沒有搶到耗子尾汁的商標注冊權,但是必須得蹭一波馬師傅的熱度,下面就是閃電五連鞭的教學環節,你准備好了嗎!

   在正式內容開始前先甩兩篇關於類加載機制和內存布局的文章,因為今天的內容多少與這兩篇文章有直接的聯系,對這方面還比較薄弱的朋友可以先看看,地址我放在下面。

jvm┃java內存區域,跳槽大廠必會知識點!

moon不講武德!!!一個類加載機制給面試官說蒙了!!

   今天本文的內容就針對剛剛模擬面試兩個問題

   1.對象的創建過程

   2.對象的內存布局

對象的創建過程

以下內容基於HotSpot VM 分代模型

這張圖其實就能完整的說明一個對象的創建過程到底發生了什么,很多朋友可能一下看不懂,那么我們就跟着左上角的一步一步來:

  1. 一個對象new出來先判斷線程棧是否能分配下
    • 如果能分配下,直接分配在棧中。
    • 如果分配不下則進行第二步。
  2. 判斷該對象是否足夠大
    • 如果足夠大,則直接進入老年代。
    • 如果不夠大,則進行第三步。
  3. 判斷創建對象的線程的TLAB(本地線程緩沖區)空間是否足夠
    • 如果足夠,直接分配在TLAB中。
    • 如果不夠,則進入Eden區中其他空間。然后進行第四步。
  4. GC清除
    • 如果清除掉了該對象,則直接結束。
    • 如果沒有清除掉對象,進行第5步。
  5. 此刻對象進入Survivor 1 區,判斷年齡是否足夠大
    • 如果年齡足夠大,則直接進入old區域。
    • 如果年齡不夠大,則進入Survivor 2 區,然后進入第4步,循環往復。

   通過這張流程圖和步驟解析大家應該對一個對象的創建過程有一個很清晰的概念了,但是其中還是有很多小細節會被忽略,為什么jvm會在對象的創建過程中大作文章,會分這么多種情況?為了讓大家更深入的能夠理解它,我們就再來看看下面這幾個問題:

  1. 為什么對象會選擇先分配在棧中?

   首先棧是線程私有的,將對象優先分配在棧中,可以通過pop直接將對象的所有信息,空間直接清除,當線程消亡的時候也可以直接清理這一塊兒TLAB區域。

  1. 為什么jvm會讓大對象會直接進入老年代?

   大對象需要連續的空間來存儲,如果不存入老年代對jvm說就可能是一個負擔,如果沒有足夠的空間就有可能導致提前觸發gc來清理空間來安置大對象。

  1. 為什么會選擇先進入TLAB?

   TLAB是線程本地緩沖區,TLAB的好處就是防止不同線程創建對象選擇同一塊兒內存區域而產生競爭,會使其概率大大減少。

  1. 為什么會有兩個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,下期見~


免責聲明!

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



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