精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Object o = new Object() 占用多少字節?

jf_ro2CN3Fa ? 來源:芋道源碼 ? 2023-11-01 15:47 ? 次閱讀


前言

我們來分析一下堆內布局以及Java對象在內存中的布局吧。

基于 Spring Boot + MyBatis Plus + Vue & Element 實現的后臺管理系統 + 用戶小程序,支持 RBAC 動態權限、多租戶、數據權限、工作流、三方登錄、支付、短信、商城等功能

  • 項目地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 視頻教程:https://doc.iocoder.cn/video/

對象的指向

先來看一段代碼:

packagecom.zwx.jvm;

publicclassHeapMemory{
privateObjectobj1=newObject();

publicstaticvoidmain(String[]args){
Objectobj2=newObject();
}
}

上面的代碼中,obj1 和obj2在內存中有什么區別?

我們先來回憶一下JVM系列1的文章中有提到,方法區存儲每個類的結構,比如:運行時常量池、屬性和方法數據,以及方法和構造函數等數據。所以我們這個obj1是存在方法區的,而new會創建一個對象實例,對象實例是存儲在堆內的,于是就有了下面這幅圖(方法區指向堆 ):

4bdfef78-7881-11ee-939d-92fbcf53809c.png

而obj2 是屬于方法內的局部變量,存儲在Java虛擬機棧內的棧幀中的局部變量表內,這就是經典的棧指向堆

4beaddd4-7881-11ee-939d-92fbcf53809c.png

這里我們再來思考一下,我們一個變量指向了堆,而堆內只是存儲了一個實例對象,那么堆內的示例對象是如何知道自己屬于哪個Class,也就是說這個實例是如何知道自己所對應的類元信息的呢?這就涉及到了一個Java對象在內存中是如何布局的。

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實現的后臺管理系統 + 用戶小程序,支持 RBAC 動態權限、多租戶、數據權限、工作流、三方登錄、支付、短信、商城等功能

  • 項目地址:https://github.com/YunaiV/yudao-cloud
  • 視頻教程:https://doc.iocoder.cn/video/

Java內存模型

對象內存中可以分為三塊區域:對象頭(Header),實例數據(Instance Data)和對齊填充(Padding),以64位操作系統為例(未開啟指針壓縮的情況) Java對象布局如下圖所示:

4c000240-7881-11ee-939d-92fbcf53809c.png

其中對象頭中的Mark Word中的詳細信息在文章synchronized鎖升級原理中有詳細介紹。上圖中的對齊填充不是一定有的,如果對象頭和實例數據加起來剛好是8字節的倍數,那么就不需要對齊填充。

知道了Java內存布局,那么我們來看一個面試問題

Object obj=new Object()占用字節

這是網上很多人都會提到的一個問題,那么結合上面的Java內存布局,我們來分析下,以64位操作系統為例,new Object()占用大小分為兩種情況:

  • 未開啟指針壓縮 占用大小為:8(Mark Word)+8(Class Pointer)=16字節
  • 開啟了指針壓縮(默認是開啟的) 開啟指針壓縮后,Class Pointer會被壓縮為4字節,最終大小為:8(Mark Word)+4(Class Pointer)+4(對齊填充)=16字節

結果到底是不是這個呢?我們來驗證一下。首先引入一個pom依賴:

<dependency>
<groupId>org.openjdk.jolgroupId>
<artifactId>jol-coreartifactId>
<version>0.10version>
dependency>

然后新建一個簡單的demo:

packagecom.zwx.jvm;

importorg.openjdk.jol.info.ClassLayout;

publicclassHeapMemory{
publicstaticvoidmain(String[]args){
Objectobj=newObject();
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
}
}

輸出結果如下:4c14f07e-7881-11ee-939d-92fbcf53809c.png最后的結果是16字節,沒有問題,這是因為默認開啟了指針壓縮,那我們現在把指針壓縮關閉之后再去試試。

-XX:+UseCompressedOops開啟指針壓縮
-XX:-UseCompressedOops關閉指針壓縮
4c20b5f8-7881-11ee-939d-92fbcf53809c.png

再次運行,得到如下結果:

4c3aa47c-7881-11ee-939d-92fbcf53809c.png

可以看到,這時候已經沒有了對齊填充部分了,但是占用大小還是16位。

下面我們再來演示一下如果一個對象中帶有屬性之后的大小。

新建一個類,內部只有一個byte屬性:

packagecom.zwx.jvm;

publicclassMyItem{
bytei=0;
}

然后分別在開啟指針壓縮和關閉指針壓縮的場景下分別輸出這個類的大小。

packagecom.zwx.jvm;

importorg.openjdk.jol.info.ClassLayout;

publicclassHeapMemory{
publicstaticvoidmain(String[]args){
MyItemmyItem=newMyItem();
System.out.println(ClassLayout.parseInstance(myItem).toPrintable());
}
}

開啟指針壓縮,占用16字節:4c5338fc-7881-11ee-939d-92fbcf53809c.png關閉指針壓縮,占用24字節:

4c5e2f8c-7881-11ee-939d-92fbcf53809c.png

這個時候就能看出來開啟了指針壓縮的優勢了,如果不斷創建大量對象,指針壓縮對性能還是有一定優化的。

對象的訪問

創建好一個對象之后,當然需要去訪問它,那么當我們需要訪問一個對象的時候,是如何定位到對象的呢?目前最主流的訪問對象方式有兩種:句柄訪問直接指針訪問 。

  • 句柄訪問 使用句柄訪問的話,Java虛擬機會在堆內劃分出一塊內存來存儲句柄池,那么對象當中存儲的就是句柄地址,然后句柄池中才會存儲對象實例數據和對象類型數據地址。4c694bc4-7881-11ee-939d-92fbcf53809c.png
  • 直接指針訪問(Hot Spot虛擬機采用的方式) 直接指針訪問的話對象中就會直接存儲對象類型數據。4c752e12-7881-11ee-939d-92fbcf53809c.png

句柄訪問和直接指針訪問對比

上面圖形中我們很容易對比,就是如果使用句柄訪問的時候,會多了一次指針定位,但是他也有一個好處就是,假如一個對象被移動(地址改變了),那么只需要改變句柄池的指向就可以了,不需要修改reference對象內的指向,而如果使用直接指針訪問,就還需要到局部變量表內修改reference指向。

堆內存

上面我們提到,在Java對象頭當中的Mark Word存儲了對象的分代年齡,那么什么是分代年齡呢?

一個對象的分代年齡可以理解為垃圾回收次數,當一個對象經過一次垃圾回收之后還存在,那么分代年齡就會加1,在64位的虛擬機中,分代年齡占了4位,最大值為15。分代年齡默認為0000,隨著垃圾回收次數,會逐漸遞增。

Java堆內存中按照分代年齡來劃分,分為Young區和Old區,對象分配首先會到Young區,達到一定分代年齡(-XX:MaxTenuringThreshold可以設置大小,默認為15)就會進入Old區(注意:如果一個對象太大,那么就會直接進入Old區 )。

之所以會這么劃分是因為如果整個堆只有一個區的話,那么垃圾回收的時候每次都需要把堆內所有對象都掃描一遍,浪費性能。而其實大部分Java對象的生命周期都是很短的,一旦一個對象回收很多次都回收不掉,可以認為下一次垃圾回收的時候可能也回收不掉,所以Young區和Old區的垃圾回收可以分開進行,只有當Young區在進行垃圾回收之后還是沒有騰出空間,那么再去觸發Old區的垃圾回收。4c879a70-7881-11ee-939d-92fbcf53809c.png

Young區

現在拆分成了Young區,那我們看下面一個場景,下面的Young是經過垃圾回收之后的一個概圖:4c9cf3ac-7881-11ee-939d-92fbcf53809c.png假如說現在來了一個對象,要占用2個對象的大小,會發現放不下去了,這時候就會觸發GC(垃圾回收),但是一旦觸發了GC(垃圾回收),對用戶線程是有影響的,因為GC過程中為了確保對象引用不會不斷變化,需要停止所有用戶線程,Sun把這個事件稱之為:Stop the World(STW)。這些在下一篇講解垃圾回收的時候會詳細介紹,這里先不深入。

所以說一般是越少GC越好,而實際上上圖中可以看到至少還可以放入3個對象,只要按照對象都按照順序放好,那么是可以放得下的,所以這就產生了問題了,明明有空間,但是因為空間不連續,導致對象申請內存失敗,導致觸發GC 了,那么如何解決這種問題呢?

解決的思路就是把Young區的對象按順序放好,所以就產生了一個方法,把Young區再次劃分一下,分為2個區:Eden區Survivor區 。4ca8eb3a-7881-11ee-939d-92fbcf53809c.png具體操作是:一個對象來了之后,先分配到Eden區,Eden區滿了之后,觸發GC,經過GC之后,為了防止空間不連續,把幸存下來的對象復制到Survivor區,然后Eden區就可以完整清理掉了,當然這么做是有一個前提的,就是大部分對象都是生命周期極短的,基本一次垃圾回收就可以把Eden區大部分對象回收掉 (這個前提是經過測試總結得到的)。

觸發GC的時候Survivor區也會一起回收,并不是說單獨只觸發Eden區,但是這樣問題又來了,Eden區是保證空間基本連續了,但是Survivor區又可能產生空間碎片,導致不連續了,所以就又把Survivor區給一分為二了:4cc3b302-7881-11ee-939d-92fbcf53809c.png這個時候工作流程又變成這樣了:首先還是在Eden區分配空間,Eden區滿了之后觸發GC,GC之后把幸存對象 復制到S0區(S1區是空的),然后繼續在Eden區分配對象,再次觸發GC之后如果發現S0區放不下了(產生空間碎片,實際還有空間),那么就把S0區對象復制到S1區,并把幸存對象也復制到S1區,這時候S0區是空的了,并依次反復操作,假如說S0區或者S1區空間對象復制移動了之后還是放不下,那就說明這時候是真的滿了,那就去老年區借點空間過來(這就是擔保機制 ,老年代需要提供這種空間分配擔保),假如說老年區空間也不夠了,那就會觸發Full GC,如果還是不夠,那就會拋出OutOfMemeoyError異常了。

注意:為了確保S0和S1兩個區域之間每次復制都能順利進行,S0和S1兩個區的大小必須要保持一致,而且同一時間有一個區域一定是空的。雖然說這種做法是會導致了一小部分空間的浪費,但是綜合其他性能的提升來說,是值得的。

Old區

當Young區的對象達到設置的分代年齡之后,對象會進入Old區,Old區滿了之后會觸發Full GC,如果還是清理不掉空間,那么就拋出OutOfMemeoyError異常。

名詞掃盲

上面提到了很多新的名詞,而實際上很多這種名詞還有其他叫法,這個還是覺得有必要了解一下。

  • 垃圾回收:簡稱GC。
  • Minor GC:針對新生代的GC
  • Major GC:針對老年代的GC,一般老年代觸發GC的同時也會觸發Minor GC,也就等于觸發了Full GC。
  • Full GC:新生代+老年代同時發生GC。
  • Young區:新生代
  • Old區:老年代
  • Eden區:暫時沒發現有什么中文翻譯(伊甸園?)
  • Surcivor區:幸存區
  • S0和S1:也稱之為from區和to區,注意from和to兩個區是不斷互換身份的,且S0和S1一定要相等,并且保證一塊區域是空的

一個對象的人生軌跡圖

從上面的介紹大家應該有一個大致的印象,一個對象會在Eden區,S0區,S1區,Old區不斷流轉(當然,一開始就會被回收的短命對象除外),我們可以得到下面的一個流程圖:4cd80a64-7881-11ee-939d-92fbcf53809c.png

總結

本文主要介紹了一個Java對象在堆內是如何存儲的,并結合Java對象的內存布局示范了一個普通對象占用大小問題,然后還分析了堆內的空間劃分以及劃分原因,本文中涉及到了GC相關知識均沒有深入講解,關于GC及GC算法和GC收集器等相關知識將放在下一篇進行詳細分析。



聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 數據
    +關注

    關注

    8

    文章

    6891

    瀏覽量

    88826
  • 函數
    +關注

    關注

    3

    文章

    4305

    瀏覽量

    62430
  • 收集器
    +關注

    關注

    0

    文章

    30

    瀏覽量

    3126

原文標題:Object o = new Object() 占用多少字節?

文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    在通用的 class 調用中定義多個 new object

    在通用的 class 調用中定義多個 new object  在INC中定義如下: if ($con == "") { $q = new
    發表于 01-11 09:19

    proteus的object作用

    proteus中object有什么作用,在實際電路中如何連接
    發表于 06-04 11:15

    Open the RTOS Object View (ROV)

    Go to menu Tools -> RTOS Object View (ROV) to open ROV In RTOS Object View expand lcdSmartRF06EB_CC2650F128.out這個在ccs中怎么打開?沒找到在哪?希望大神給些建
    發表于 06-21 17:31

    Vuforia 4.0 beta的Object Recognition功能使用

    ARVR技術交流群:129340649歡迎加入!Vuforia 4.0 beta終于出來了,其中有個比較新穎的功能,那就是Object Recognition。這個功能對于有些行業是很有幫助
    發表于 09-19 18:13

    在STM32上使用cJson或Jansson創建object

    在STM32上使用cJson或Jansson創建object,添加的子object太多時會創建失敗,比如生產的字符串總長度為770字節,此時需要修改startup_stm32xxx.s文件中
    發表于 01-11 06:25

    Java Object Serialization Spec

    Java Object Serialization SpecificationObject serialization in the Java™system is the process
    發表于 10-14 17:39 ?7次下載

    Object-Oriented Programming in

    This chapter applies a different programming paradigm to G: Object-Oriented Programming(OOP). New
    發表于 03-02 14:18 ?28次下載

    什么是CORBA (Common Object Reques

    什么是CORBA (Common Object Request Broker Architecture)  英文縮寫: CORBA (Common Object Request Broker Architecture) 中文譯名: 通用對象請求
    發表于 02-22 11:48 ?945次閱讀

    Video-Object-Segmentation-from-MPEG4講解

    本文檔內容介紹了基于Video-Object-Segmentation-from-MPEG4講解,供參考
    發表于 03-15 10:32 ?2次下載

    Object中有哪一些公共方法

    大家在學習java的時候,一定遇到過Object類,因為在java單一繼承體系中Object類是根類,所有的類都會繼承它,并擁有Object的公共方法,意味著在java的面向對象的世界中,所有對象都擁有這些方法,非常通用。
    發表于 03-02 09:57 ?767次閱讀

    C# 中的 Object 虛方法 怎樣重寫

    在 C# 中 Object 是所有類的基類,所有的結構和類都直接或間接的派生自它。
    發表于 03-18 11:51 ?1018次閱讀

    圖形界面介紹:GUI上的按鍵是Find/Select Object

    今天我們要介紹的GUI上的按鍵是Find/Select Object Form,這是一個平時我們比較常用的一個按鍵,用于尋找符合要求的Object。在Innovus中,大家可能平時更喜歡用dbGet
    的頭像 發表于 05-19 16:43 ?2658次閱讀

    Qt“靈魂”之Meta-Object系統

    Meta-Object即是Qt的元對象系統,下文都以元對象系統進行描述。在Qt中,具有標志性特征的則是信號和槽函數機制,該機制的背后實現本質上則是元對象系統。編寫Qt代碼的時候,在定義類的時候,需要放置一個Q_OBJECT,為什么呢?后文會描述到,例如如下代碼。
    的頭像 發表于 02-10 13:50 ?1834次閱讀

    Object類中的所有方法

    Object 類屬于 java.lang 包,此包下的所有類在使用時無需手動導入,系統會在程序編譯期間自動導入。Object 類是所有類的基類,當一個類沒有直接繼承某個類時,默認繼承Object
    的頭像 發表于 10-13 11:50 ?500次閱讀
    <b class='flag-5'>Object</b>類中的所有方法

    基于FPGA加速的bird-oid object算法實現

    Bird-oid object 簡稱Boids模型,是美國的一個圖形計算機科學家Craig Reynolds在 1986 年開發出來的。
    的頭像 發表于 04-09 11:05 ?613次閱讀
    基于FPGA加速的bird-oid <b class='flag-5'>object</b>算法實現