成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java 對象大小的精確計算方法

開發 后端
日常使用Java進行業務開發時,經常因為錯誤的估算導致大量的內存空間在無形之間被浪費了,所以今天筆者就基于這篇文章來聊聊一個Java對象的大小。

日常使用Java進行業務開發時,我們基本不關心一個Java對象的大小,所以經常因為錯誤的估算導致大量的內存空間在無形之間被浪費了,所以今天筆者就基于這篇文章來聊聊一個Java對象的大小,希望對讀者日常堆內存評估有所幫助。

一、Java對象構成詳解

1.整體構成概述

我們這里就以Hotspot虛擬機來探討Java對象的構成,如下所示,可以看到Java對象的整體構成分為:

  • 對象頭(Header)
  • 實例數據(Instance Data)
  • 對齊填充(Padding)

2.對象頭

(1) Mark World

而對象頭是由兩部分組成的,第一部分用于存儲對象自身的數據,也就是我們常說的Mark World,它記錄著一個對象的如下信息:

  • 哈希碼(hashCode)
  • GC分代年齡
  • 鎖狀態標志
  • 線程持有鎖
  • 偏向鎖id
  • 偏向時間戳

(2) 類型指針

再來說說類型指針,它記錄著當前對象的元數據的地址,虛擬機可通過這個指針確定當前對象屬于哪個類的實例,也就是說如果我們希望獲得這個對象的元數據信息是可以通過類型指針定位到。 需要注意的是,在JDK8版本默認情況下,Mark World默認開啟了指針壓縮,這使得這一部分在64位的操作系統中的情況下,長度由原來的8個字節(64位)變為4個字節(32位)。

(3) 數組長度

最后一部分就是數組長度,如果當前對象是基本類型的數組,那么這4位則是記錄數組的長度,為什么說是基本類型呢?原因很簡單,普通Java對象的的大小是可以通過元數據信息計算獲得,而基本類型的數組卻卻無法從元數據信息中計算獲得,所以我們就需要通過4個字節記錄一下數組的長度以便計算。

3.實例數據

這一點就不多說了,這就是對象真正存儲的有效信息,這些實例數據可以是從父類繼承也可以是自定義字段,因為實例數據可能存在多個,Hotspot虛擬機定義了實例對象內存分配的先后順序:

  • long/double(8字節)
  • int(4字節)
  • short/char(2字節)
  • byte/boolean(1字節)
  • oops(Ordinary Object Pointers 普通對象指針)

4.對齊填充

Hotspot虛擬機為了保證在指針壓縮的情況下,32字節的空間仍然表示32G的內存空間地址,用到了8位對齊填充的思想,既保證了緩存命中率可以記錄更多的對象,又能記錄更多的對象地址。 因為指針壓縮涉及的知識點比較多,筆者后續會單獨開一個篇幅進行補充,這里我們有先說一下對其填充,假設我們現在有這樣一個Java對象,可以看到在實例數據部分,它有8字節的long變量和4字節的int變量,合起來是12字節:

public 
class 
Obj 
{
    
private 
long id;

    
private 
int  age;
}

而8位對齊填充的意思就是實例數據部分的和要能夠被16整除,所以對于這個對象的實例部分,我們還需要補充4個字節做到8位的對齊填充:

二、基于JOL了解Java對象的構成

1.前置步驟

了解了Java對象的組成之后,我們不妨通過JOL(Java Object Layout)來印證一下筆者的觀點,所以我們需要在項目中引入下面這個依賴開始本次的實驗:

  <dependency>
   <groupId>org.openjdk.jol</groupId>
   <artifactId>jol-core</artifactId>
   <version>0.10</version>
  </dependency>

2.空對象

首先是一個空對象EmptyObj ,可以看到這個對象沒有任何成員變量:

class 
EmptyObj 
{


}

我們都知道默認情況下,JDK8是開啟指針壓縮的,可以看到object header總共12字節,其中Mark World占了前8字節(4+4),類型指針占了4字節,加起來是12字節,而Java對象要求16位對齊,所以需要補齊4位,總的結果是16字節:

com.sharkChili.webTemplate.EmptyObj object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

我們再來看看關閉指針的壓縮的結果,首先我們設置JVM參數將指針壓縮關閉:

-XX:-UseCompressedClassPointers

此時我們就發現指針由原來是object header多了4位,原本被壓縮的指針占用空間被還原了(offset為8-12的部分),總的計算結果為16字節,無需對齊填充:

com.sharkChili.webTemplate.EmptyObj object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           c0 34 b8 1c (11000000 00110100 10111000 00011100) (481834176)
     12     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

3.數組對象

我們再來看看數組對象,在默認開啟指針壓縮的情況下,我們創建了一個長度為3的數組:

com.sharkChili.webTemplate.EmptyObj object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           c0 34 b8 1c (11000000 00110100 10111000 00011100) (481834176)
     12     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

可以看到:

  • Mark World占了8字節
  • 指針4字節(offfset為8這一部分)
  • offset為12這一部分也有了4字節的空間,記錄了一個值3即數組長度

所以8+4+4=16,對象頭剛剛好8位對齊,故無需對齊填充。

再看看實例數據部分(offset為16)這一部分,因為數組中有3個整形所以長度size為12,需要補充4字節達到8位對齊,最終這個數組對象的長度為16(對象頭)+16(實例數據部分)=32字節:

[I object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           6d 01 00 f8 (01101101 00000001 00000000 11111000) (-134217363)
     12     4        (object header)                           03 00 00 00 (00000011 00000000 00000000 00000000) (3)
     16    12    int [I.<elements>                             N/A
     28     4        (loss due to the next object alignment)
Instance size: 32 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

我們再來看看關閉指針壓縮的結果,可以看到mark word和指針都占了8位,加上數組長度的4位,最終對象頭為20位,8位對齊后為24位。 同理實例部分還是12字節的數組元素大小加4字節的8對齊字節,關閉指針壓縮后的對象大小為40字節:

[I object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           68 0b 85 1c (01101000 00001011 10000101 00011100) (478481256)
     12     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     16     4        (object header)                           03 00 00 00 (00000011 00000000 00000000 00000000) (3)
     20     4        (alignment/padding gap)                  
     24    12    int [I.<elements>                             N/A
     36     4        (loss due to the next object alignment)
Instance size: 40 bytes
Space losses: 4 bytes internal + 4 bytes external = 8 bytes total

4.帶有成員變量的對象

我們再來說說帶有成員變量的Java對象,也就是我們日常使用的普通Java對象:

class 
NormalObject 
{
    
int a;
    
short b;
    
byte c;
   

}

默認開啟指針壓縮的情況下,對象頭為8+4=12字節,而實例數據部分,參考上文的實例數據順序,我們的NormalObject的實例數據內存分配順序為int、short、byte。 虛擬機為了更好的利用內存空間,看到對象頭還差4字節才能保證對象頭8位對齊填充,故將實例數據int作為對齊填充移動至對象頭。

所以實例數據部分長度是2+1+5(對齊填充),最終在指針壓縮的情況下,當前對象長度為24字節。

com.sharkChili.webTemplate.NormalObject object internals:
 OFFSET  SIZE    TYPE DESCRIPTION                               VALUE
      0     4         (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4         (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4         (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4     int NormalObject.a                            0
     16     2   short NormalObject.b                            0
     18     1    byte NormalObject.c                            0
     19     5         (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 5 bytes external = 5 bytes total

同理,關閉指針壓縮,相比讀者現在也知道如何計算了,筆者這里就不多贅述了,答案是是對象頭8+8,實例數據4+2+1+1(對齊填充),即關閉指針壓縮情況下,當前普通對象大小為24字節:

com.sharkChili.webTemplate.NormalObject object internals:
 OFFSET  SIZE    TYPE DESCRIPTION                               VALUE
      0     4         (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4         (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4         (object header)                           10 35 0b 1d (00010000 00110101 00001011 00011101) (487273744)
     12     4         (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     16     4     int NormalObject.a                            0
     20     2   short NormalObject.b                            0
     22     1    byte NormalObject.c                            0
     23     1         (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 1 bytes external = 1 bytes total

5.帶有數組的對象

最后我們再來看看帶有數組的對象:

class NormalObject {
    int a;
    short b;
    byte c;
    int[] arr = new int[3];

}

先來看看開啟指針壓縮8+4+int變量作為對齊填充即16字節,注意很多讀者會認為此時還需要計算數組長度,實際上數組長度記錄的是當前對象為數組情況下的數組的長度,而非成員變量的數組長度,所以我們的對象頭總的大小就是16。

然后實例數據部分4+2+1+1(對齊填充),最后就是數組引用4+4(對齊填充),最終結果為16+8+8即32:

com.sharkChili.webTemplate.NormalObject object internals:
 OFFSET  SIZE    TYPE DESCRIPTION                               VALUE
      0     4         (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4         (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4         (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4     int NormalObject.a                            0
     16     2   short NormalObject.b                            0
     18     1    byte NormalObject.c                            0
     19     1         (alignment/padding gap)                  
     20     4   int[] NormalObject.arr                          [0, 0, 0]
Instance size: 24 bytes
Space losses: 1 bytes internal + 0 bytes external = 1 bytes total

關閉指針壓縮情況下,對象頭8+8。實例數據4+2+1+1(對齊填充),再加上數組引用的4字節+4字對齊填充,最終計算結果為32字節。

com.sharkChili.webTemplate.NormalObject object internals:
 OFFSET  SIZE    TYPE DESCRIPTION                               VALUE
      0     4         (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4         (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4         (object header)                           48 35 f8 1c (01001000 00110101 11111000 00011100) (486028616)
     12     4         (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     16     4     int NormalObject.a                            0
     20     2   short NormalObject.b                            0
     22     1    byte NormalObject.c                            0
     23     1         (alignment/padding gap)                  
     24     4   int[] NormalObject.arr                          [0, 0, 0]
     28     4         (loss due to the next object alignment)
Instance size: 32 bytes
Space losses: 1 bytes internal + 4 bytes external = 5 bytes total

小結

總的來說要想獲取Java對象的大小,我們只需按照如下步驟即可精確計算:

  • mark world 8位。
  • 確認是否開啟指針壓縮,以計算類型指針大小。
  • 是否是數組,若是則增加4字節數組長度位。
  • 計算對象頭總和進行8位填充。
  • 實例數據按照順序排列并計算總和,并進行8位填充。
  • 引用數據計算總和,并進行8位填充。
  • 綜合上述計算結果。
責任編輯:趙寧寧 來源: 寫代碼的SharkChili
相關推薦

2017-11-20 11:10:26

數據中心機房設備

2010-08-04 15:01:07

Flex Panel控

2018-01-18 21:54:10

云計算公共云云服務

2009-09-27 10:48:54

UPS電池容量

2020-03-24 09:06:45

Java對象大小

2009-11-25 13:45:06

linux服務器并發處理數

2018-11-06 10:08:34

無線AP網絡帶寬無線網絡

2017-07-27 10:49:48

高密WiFi終端

2018-08-15 09:13:27

布線系統線纜用量

2011-07-22 09:34:33

蓄電池組線纜線損

2018-08-22 10:32:15

虛擬桌面服務器

2010-01-25 10:45:25

服務器虛擬化硬件配置需

2025-01-16 07:00:00

AOPSpringBoot后端

2023-10-26 09:20:29

2018-07-18 10:18:01

數據中心負荷計算系統

2010-07-17 15:46:03

WiMAX

2014-05-13 09:53:24

算法π值

2009-12-03 09:59:20

JVM概念Java對象引用類型

2022-11-02 15:28:55

MySQL執行計劃B+樹

2011-05-07 10:47:29

Oracle大小寫
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩欧美二区 | 午夜视频网站 | 97久久精品午夜一区二区 | 久久机热 | 成人在线免费网站 | www视频在线观看 | 国产精品久久久久久久久久久久 | 国产在线中文字幕 | 欧美大片一区 | 中文字幕在线观看国产 | 亚洲女人天堂网 | 中文字幕乱码亚洲精品一区 | 精品国产乱码久久久久久久久 | 亚洲 中文 欧美 日韩 在线观看 | 色综合视频在线 | 在线看亚洲 | 午夜免费| 久久久综合 | 99精品视频免费在线观看 | 成人国产综合 | 国产精品久久久久久福利一牛影视 | 在线免费观看a级片 | 91精品久久久久久久久久入口 | 亚洲精品一区二区三区中文字幕 | 在线一区 | 国产一区二区三区四区五区3d | 日本久久网站 | 久久国产一区 | 午夜精品一区二区三区三上悠亚 | 国产精品欧美一区二区 | 亚洲免费视频在线观看 | 嫩草视频在线看 | 日本免费在线 | 亚洲高清在线 | 成年人视频在线免费观看 | 精品成人在线视频 | 操久久| 日本成人中文字幕 | avhd101在线成人播放 | 一级a性色生活片久久毛片波多野 | 91精品国产乱码久久久久久久久 |