• <em id="6vhwh"><rt id="6vhwh"></rt></em>

    <style id="6vhwh"></style>

    <style id="6vhwh"></style>
    1. <style id="6vhwh"></style>
        <sub id="6vhwh"><p id="6vhwh"></p></sub>
        <p id="6vhwh"></p>
          1. 国产亚洲欧洲av综合一区二区三区 ,色爱综合另类图片av,亚洲av免费成人在线,久久热在线视频精品视频,成在人线av无码免费,国产精品一区二区久久毛片,亚洲精品成人片在线观看精品字幕 ,久久亚洲精品成人av秋霞

            如何計算Java對象占堆內存中的大小

            更新時間:2023-05-26 04:34:01 閱讀: 評論:0

            桂花雨的作者-人世間紀錄片

            如何計算Java對象占堆內存中的大小
            2023年5月26日發(作者:太空蛋糕)

            如何計算Java對象占堆內存中的??

            李強,20185??職Qunar,現任?車票技術部Java開發?程師。參與構建?車票業務系統的底層技術?持體系,個?

            對并發編程、分布式系統等技術點感興趣。

            前?

            在實際?作中,我們可能會遇到需要計算某個對象占?堆內存空間??的問題。這時,就需要我們了解 Java 對象在堆

            內存中的實際存儲?式和存儲格式。本?就針對此問題展開分析,詳細介紹了 Java 對象在堆內存中的結構,從?讓?

            家能夠?便的計算出對象占?內存的??。注意:本?默認環境為 64 位操作系統,JDK 1.8JVM HotSpot

            Oop-Klass模型

            我們知道 Java 對象在內存中的訪問?式,如下圖所?:

            通過上圖,我們可以知道?個 Java 實例對象由 Java 堆中的實例數據和?法區的類型數據兩部分組成。對應到 JVM

            部,HotSpot 設計了?個 Oop-Klass 的?分模型來表??個 Java 實例對象的兩部分:

            Klass 簡單來說就是 Java 類在 HotSpot 中的 C++ 對等體,主要?于描述對象實例的具體類型。?般 JVM 在加

            class ?件時,會在?法區創建 Klass ,表?類的元數據,其包括常量池、字段、?法等。

            Oop指的是 Ordinary Object Pointer(普通對象指針)。其在 Java 創建對象實例的時候創建,?于表?對象的實

            例信息。也就是說,在 Java 應?程序運?中每創建?個 Java 對象,在 JVM 內部都會創建?個 Oop 對象來表? Java

            對象。這?有的同學可能會產?這樣的疑問:C++ 也是?種?向對象的編程語?,HotSpot 為什么不將 Java 對象直接

            映射成?個 C++ 對象,?是要拆分成兩個呢?這是因為在 C++ 中有?個概念叫虛函數表,每?個 C++ 對象都會有?個

            虛函數表。HotSpot 為了提?效率,復?虛函數表,才設計了這種 Oop-Klass 的?分模式。這個模型參考了 Smalltalk

            ,詳細論證見 Wiki

            Oop

            JVM 中,Oop 的共同基類型 oopDesc 。另外根據表?的對象類型的不同,JVM 中具有多種 oopDesc ?類,每個

            oopDesc 的?類都代表?個在 JVM 內部使?的特定對象類型。JVM Oop 主要由如下?種類型組成:

            (詳細代碼見 JDK1.8 源碼:./src/hotspot/share/oops/ )

            1.//定義Oop的抽象基類

            1.//定義Oop的抽象基類

            2.typedef class oopDesc* oop;

            3.//表??個Java實例對象

            4.typedef class instanceOopDesc* instanceOop;

            5.//定義數組Oop的抽象基類

            6.typedef class arrayOopDesc* arrayOop;

            7.//表?Java對象數組

            8.typedef class objArrayOopDesc* objArrayOop;

            9.//表?基本類型的數組

            f class typeArrayOopDesc* typeArrayOop;

            例如,當我們使? new 創建?個 Java 對象實例的時候,JVM 會創建?個 instanceOopDesc 對象來表?這個 Java

            象;同理,當我們使? new 創建?個 Java 數組實例的時候,JVM 會創建?個 arrayOopDes 對象來表?這個數組對

            象。

            Klass

            Oop ?樣,JVM 中定義了如下的 Klass 類型:

            1.//所有Klass類的基類

            2.class Klass;

            3.//描述?個Java

            4.class InstanceKlass;

            5.//專有的InstanceKlass,表?Klass

            6.class InstanceMirrorKlass;

            7.//專有的InstanceKlass,?于類加載器

            8.class InstanceClassLoaderKlass;

            9.//專有的InstanceKlass,?于表?nce的?類的Klass

            InstanceRefKlass;

            11.//描述數組類型的類的基類

            ArrayKlass;

            13.//描述對象數組類

            ObjArrayKlass;

            15.//描述基本類型數組類

            TypeArrayKlass;

            這?需要額外說明?點:1.8 中去掉了永久代(Perm),?改為了元空間(MetaSpace)。因此 JDK1.8 Oop-Klass

            型與 JDK1.7 存在較?的區別,本?以 JDK1.8 為準,JDK1.7 1.8 的詳細區別可參考:1.71.8 Oop-Klass模型。

            Java對象在堆中的布局 源碼解析

            上?我們介紹到,JVM 中通過?個 instanceOopDesc 對象來表??個 Java 實例對象。想要了解 Java 對象在內存中的

            布局,只需要了解 instanceOopDesc 類的結構即可。由于 instanceOopDesc 類是 oopDesc 類的?類,其代碼?部分

            位于 oopDesc 類中。

            我們直接來看 oopDesc 類的代碼:./src/hotspot/share/oops/ 中,它包含兩個數據成員:

            1.class oopDesc {

            2.private:

            3.volatile markOop _mark;

            4.union _metadata {

            5.Klass* _klass;

            6.narrowKlass _compresd_klass;

            7.} _metadata;

            8.}

            1._mark _mark?于存儲對象的 HashCode、鎖標記、偏向鎖、?旋時間、分代年齡等信息。

            2._metadata _metadata是?個指向 Klass 的指針,是?個共?體( union )。也就是說它要么是 klass 字段要么是

            compresdklass

            compresdklass

            JVM 開啟了-XX:+UCompresdClassPointers( 表?啟? Klass 指針壓縮選項, JVM 默認開啟 )選項時使?

            commpresdklass 來存儲 Klass 引?了,否則使? _klass 存儲 Klass 引?。

            注意:在數組相關的 Oop 類中,除了上述兩個數據成員外,還有?個 int 類型數據成員 length ,?于表?數組的長度。

            詳細代碼見:./src/hotspot/share/oops/ oopDesc 類本?的數據成員,我們稱之為對象頭。除了對象頭

            之外,oopDesc 還需要保存 Java 對象的實例字段。這些實例字段緊跟對象頭存儲,其起始偏移地址可通過

            instanceOopDesc 類中的函數( 位于:./src/hotspot/share/oops/)計算得出:

            1.// If compresd, the offt of the fields of the instance may not be aligned.

            2.static int ba_offt_in_bytes() {

            3.// offt computation code breaks if UCompresdClassPointers

            4.// only is true

            5.return (UCompresdOops && UCompresdClassPointers) ?

            6.klass_gap_offt_in_bytes() :

            7.sizeof(instanceOopDesc);

            8.}

            9.//./src/hotspot/share/oops/

            int klass_gap_offt_in_bytes() {

            (has_klass_gap(), "only applicable to compresd klass pointers");

            klass_offt_in_bytes() + sizeof(narrowKlass);

            13.}

            14.

            int klass_offt_in_bytes() { return offt_of(oopDesc, _metadata._klass); }

            ?例

            通過對源碼的分析,我們基本弄清了 Java 對象在 JVM 內部的內存分布,下?我們通過?個例?來更直觀地說明。

            如有如下代碼:

            1.public class Model {

            2.

            3.public static int a = 1;

            4.

            5.public int b;

            6.

            7.public Model(int b) {

            8.this.b = b;

            9.}

            10.

            11.}

            12.

            static void main(String[] args) {

            14.

            c = 10;

            modela = new Model(2);

            17.

            modelb = new Model(3);

            19.}

            那么其在內存中的布局如下圖所?:

            總結

            根據上?的學習,我們可以總結出?個 Java 對象在堆內存中的布局?致如下所?:

            注意:這?的 Padding ( 對齊填充 )是作為填充字段,為滿? Java 對象所占內存必須為 8 字節的倍數?存在的。

            1.對象頭:對象頭是 Java 對象存儲結構中最復雜的部分。它由下述?部分組成:

            (1)mark word:在 64 位系統下? 8 字節表?;32 位系統為 4 字節。

            (2)metadata64 位系統下,若 JVM 開啟 Klass 指針壓縮選項( -XX:+UCompresdClassPointersJVM 默認開啟

            此選項 ),則? 4 字節表?;若不開啟指針壓縮( -XX:-UCompresdOops )則? 8 字節表?;32 位系統則使? 4

            字節表?。 指針壓縮的?的就是為了節省內存,若有同學對具體的壓縮算法感興趣可參考:CompresdOops

            (3)Length:若當前對象為數組,那么對象頭中除了上述兩部分內容外,還會有 4 字節的內容?于表?存儲數組的長度

            信息;若當前對象不為數組,則對象頭中不存在此項信息。

            2.實例數據:實例數據中存儲的就是當前對象的實例字段。字段的存儲類型有基本類型和引?類型兩種,它們對應的存

            儲??如下圖:

            其中 ref 表?引?類型,引?類型實際上是?個地址指針,其在 32 位系統中,占? 4 字節,64 位系統中,如果開啟了

            指針壓縮( -XX:+UCompresdOops JVM 默認開啟此選項 )則占? 4 字節,若不開啟則占? 8 字節。 此外,實例

            數據中的字段既包括從?類繼承的,也包括?類本?定義的。這些字段在內存中的存儲順序會受到虛擬機分配策略參數

            FieldsAllocationStyle )和字段在 Java 源碼中定義順序的影響。HotSpot 中有三種虛擬機分配策略,見如下代碼注

            釋(源碼位置:./hotspot/share/classfile/):

            1.// Rearrange fields for a given allocation style

            2.if( allocation_style == 0 ) {

            3.// Fields order: oops, longs/doubles, ints, shorts/chars, bytes, padded fields

            4.......

            5.} el if( allocation_style == 1 ) {

            6.// Fields order: longs/doubles, ints, shorts/chars, bytes, oops, padded fields

            7.......

            8.} el if( allocation_style == 2 ) {

            9.// Fields allocation: oops fields in super and sub class are together.

            10.......

            11.}

            從中可以看出這三種策略的字段排列順序不同:

            1.策略0oops ( Ordinary Object Pointers ,普通對象指針,也就是引?類型 )在基本數據類型前?, 其后依次是

            longs/doubles, ints, shorts/chars, bytes , 最后是填充字段, 以滿?對齊要求。

            2.策略1oops 在基本數據類型之后。

            3.策略2:?類中的引?類型與?類中的引?類型放在?起。JVM 默認分配策略為 1 ,可通過參數 -

            XX:FieldsAllocationStyle=2 ,將分配策略變更為 2 。策略 0 和策略 1 區別不?,都是將基本數據類型按照從?到?的

            ?式排序,這樣可以降低空間開銷。?策略 3 將?類和?類的引?放在?起可以增加 GC 效率,試想在 GC 掃描引?

            時,由于?類和?類的引?連續,可能只需要掃描?個 cache line 即可,若?類和?類的引?不連續,則需要掃描多個

            cache line ;另外連續的內存引?還可減少 OopMap 的個數,從?達到提? GC 效率的?的。關于虛擬機內存分配策略

            的詳細代碼解讀可參考:jvm源碼分析之oop-klass對象模型,這?不再展開細說。在滿?上述的虛擬機分配策略前提條

            件下,?般?類的字段會在?類的字段之前,但是 JVM 也提供了參數 -XX:+/-CompactFields ( 默認開啟 ),來允許將?

            類實例字段中的?對象插?到?類變量的縫隙中。 總體來看,實例數據的??就是對象的各個實例字段的??之和。

            對齊填充:JVM 要求對象的??必須是 8 字節的整數倍,因此當對象頭+實例數據的??不滿? 8 字節的整數倍時,

            就需要增加填充數據,以滿?此條件。按照 8 字節對齊,是底層 CPU 數據總線讀取內存數據的要求。通常 CPU 按照

            字長來讀取數據,?個數據若不對齊則可能需要 CPU 讀取兩次,若進?了對齊,則?次性即可取出?標數據,這將會

            ??節省 CPU 資源,因此對象??需要對齊。

            通過上?的介紹,我們基本就可以計算出?個 Java 對象占?堆內存的??了。假如有如下代碼:

            1.public class People {

            2.int age = 20;

            3.

            4.String name = "XiaoMing";

            5.}

            6.public class Person extends People {

            7.boolean married = fal;

            8.

            9.long birthday = 3283520940L;

            10.

            tag = 'a';

            12.

            sallary = 4700.00d;

            14.}

            那么?個 Person 對象的堆內存??可以計算得出:

            對象頭:8( mark )+4( Klass 指針 )=12

            對象頭:8( mark )+4( Klass 指針 )=12

            實例數據:4( age )+4( name )+1( married )+8( birthday )+2( tag )+8( sallay )=27那么此時 Person 對象的??為:

            12+27+1( padding )=40 此時計算的 name 是?個指向 String 對象的指針,我們還需要加上 name 對象的??:8(

            mark )+4( Klass 指針 )+4( hash )+4( value[] )+4( padding )=24 其中 value[] 是?個 char 數組的指針,因此需要再加上

            此數組的長度:8( mark )+4( Klass 指針 )+4( length )+8*2( 8 char )+0( padding )=32。綜上,?個 Person 對象占?堆

            內存的??為 40+24+32=96 字節。

            HSDB

            通過上?章節的學習,我們已經 get 到如何計算?個 Java 對象占?的堆內存??,但是如何來驗證我們計算的是否正

            確呢?其實 HotSpot 已經為我們提供了?個?具來查詢運?時對象的 Oops 結構,那就是 HSDB

            1.我們在命令?中運?如下程序:

            1.public static void main(String[] args) throws InterruptedException {

            2.

            3.Person person = new Person();

            4.

            5.(60*1000);

            6.

            7.n("end");

            8.}

            2.使? JPS 獲取運?的 Java 進程號,運?如下指令啟動 HSDB sudo java -cp $JAVA_HOME/lib/

            ,然后選擇 File->Attach to HotSpot process并輸?進程 ID

            3.此時會顯?對應進程的線程信息。點擊Tools->Object Histogram即可打開堆的對象列表。在列表中輸?想要查看的類

            名稱進?搜索:

            雙擊對應的對象,然后點擊 Inspect 按鈕即可看到該對象的 Oop 結構信息:

            4.也可以點擊 Tools->Class Browr打開類信息列表,并搜索想查看類信息,也可對象中各個字段的偏移量。

            代碼計算內存占?的?法

            前?我們介紹了 Java 對象在堆中的內存布局之后,就可?動計算出?個 Java 對象占?的堆內存??,但是假如我們需

            要在代碼中計算?個對象的內存占??該如何進?呢?這?總結了三種?式供?家參考:

            Instrumentation

            使?ectSize()?法可以?便地計算出?個運?時對象的??。關于如何獲取

            Instrumentation 這?不再贅述,我們關注?下 getObjectSize()?法的注釋:

            1./**

            2.* Returns an implementation-specific approximation of the amount of storage consumed by

            3.* the specified object. The result may include some or all of the object's overhead,

            4.* and thus is uful for comparison within an implementation but not between implementations.

            5.*

            6.* The estimate may change during a single invocation of the JVM.

            7.*

            8.* @param objectToSize the object to size

            9.* @return an implementation-specific approximation of the amount of storage consumed by the specified object

            10.* @throws interException if the supplied Object is null.

            11.*/

            getObjectSize(Object objectToSize);

            通過注釋我們可知,此?法求出的值是?個近似值,并不準確。因此這種?法只適?于同?個對象多次求??并進??

            較,不適??兩個對象之間?較。

            使?Unsafe

            java 中的 類,有?個 objectFieldOfft(Field f) ?法,表?獲取指定字段在所在實例中的起始地址偏移

            量。因此我們可以獲取指定的對象中每個字段的偏移量,并求出其中的最?值。偏移量最?的字段肯定位于實例數據中

            的最后,再使?該字段的偏移量加上該字段的實際??,就能知道該對象整體的??。 例如有如下類:

            1.public class Example {

            2.int size = 20;

            3.String name = "XiaoMing";

            4.}

            使?如下代碼計算其字段的偏移地址:

            使?如下代碼計算其字段的偏移地址:

            1.public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {

            2.Field field = laredField("theUnsafe");

            3.essible(true);

            4.Unsafe unsafe = (Unsafe) (null);

            5.

            6.Example example = new Example();

            7.

            8.Field sizeField = ss().getDeclaredField("size");

            9.long sizeAddr = FieldOfft(sizeField);

            n("size offt is:" + sizeAddr);

            11.

            nameField = ss().getDeclaredField("name");

            nameAddr = FieldOfft(nameField);

            n("name offt is:" + nameAddr);

            15.}

            結果:

            1.size offt is:12

            2.name offt is:16

            由上可知 name offt 最?為 16 ,在加上其本?的長度 4 ( String 對象的指針 ),則 Example 對象的實際??為:

            16+4+4( Padding )=24

            但是上述這種?式計算的只能是對象本?的??,并沒有計算對象中的引?類型所引?的對象的??。若想要獲取?個

            對象的完整??,則還需要寫代碼進?遞歸計算。

            使?第三??具

            這?提供?個第三?專門計算堆內存占???的?具類:

            1.

            2.arch

            3.java-sizeof

            4.0.0.5

            5.

            其中 RamUsageEstimator類提供獲取對象堆內存占???的?法,如下所?驗證我們前?章節計算的對象??:

            1.public static void main(String[] args) {

            2.People people = new People();

            3.

            4.Person person = new Person();

            5.

            6.n("people:"+(people));

            7.n("person:"+(person));

            8.

            9.}

            10.結果:

            :80

            :96

            RamUsageEstimator 類主要就是根據 JVM 規范計算對象的??,并不是根據實際的內存地址計算。因此,它存在?個

            缺點,那就是可能存在與實際??不符合的情況。

            參考資料

            1.《深?理解 Java 虛擬機》第2版,周志明,機械?業出版社;

            2. Hotspot oopsklass handle;

            3. 如何計算 Java 對象所占內存的??;

            4. Hotspot GC研究- 開篇&對象內存布局;

            5. Java 對象內存結構。

            總結

            本??先介紹了 JVM Oop-Klass 模型,這是理解 Java 內存布局的基礎,接下來講解了?個 Java 對象在堆中的結

            構,然后?簡單介紹了如何通過 HSDB 查看對象的 Oop 結構,最后介紹了?種通過代碼計算 Java 對象內存布局的?

            式。 掌握對象的內存布局是解決?作中遇到的?些諸如:評估本地內存的占?量、定位內存泄漏 Bug 等問題的基礎。

            希望?家通過閱讀本?能夠有所收獲。 本?參考了多??資料,并做了?些總結,可能會有些不正確的地?敬請指正。

            會計簡歷模板-打工仔買房記

            如何計算Java對象占堆內存中的大小

            本文發布于:2023-05-26 04:34:00,感謝您對本站的認可!

            本文鏈接:http://m.newhan.cn/zhishi/a/1685046841179303.html

            版權聲明:本站內容均來自互聯網,僅供演示用,請勿用于商業和其他非法用途。如果侵犯了您的權益請與我們聯系,我們將在24小時內刪除。

            本文word下載地址:如何計算Java對象占堆內存中的大小.doc

            本文 PDF 下載地址:如何計算Java對象占堆內存中的大小.pdf

            標簽:小對象
            相關文章
            留言與評論(共有 0 條評論)
               
            驗證碼:
            推薦文章
            排行榜
            Copyright ?2019-2022 Comsenz Inc.Powered by ? 實用文體寫作網旗下知識大全大全欄目是一個全百科類寶庫! 優秀范文|法律文書|專利查詢|
            主站蜘蛛池模板: 久久精品一偷一偷国产| 在线观看成人永久免费网站| 神马午夜久久精品人妻| 尤物视频在线播放你懂的| 日韩av在线不卡一区二区三区| 精品国产中文字幕在线看| 亚洲精品日韩在线观看| 欧洲成人午夜精品无码区久久| 中文字幕人妻无码一区二区三区| 波多野结衣一区二区三区高清| 中文字幕人妻中出制服诱惑 | 精品无码一区在线观看| 中文字幕不卡在线播放| 性夜久久一区国产9人妻| 久久久久久人妻一区二区无码Av| 国产三级精品三级在线观看| 久青草视频在线免费观看| 亚洲一区中文字幕人妻| 国产成人亚洲综合色婷婷秒播| 久久久久久99精品热久久| 无码专区 人妻系列 在线| 国产精品无遮挡猛进猛出| 日韩乱码人妻无码中文字幕视频 | 成人深夜节目在线观看| 亚洲人视频在线观看| 免费大黄网站在线观看| 九九热精品视频在线免费| 亚洲AVAV天堂AV在线网阿V| A级毛片100部免费看| 国产毛a片久久久久无码| аⅴ天堂中文在线网| 日韩精品中文字幕亚洲| 永久免费AV无码网站YY| 亚洲av午夜精品一区二区三区| 亚洲线精品一区二区三八戒| 色偷偷亚洲女人天堂观看| 青春草公开在线视频日韩| 曰韩亚洲AV人人夜夜澡人人爽| 疯狂做受XXXX高潮国产| 亚洲人成网77777香蕉| 亚洲天天堂天堂激情性色|