天天看點

JAVA記憶體使用--如何計算一個Java對象占用的位元組數

原文位址:點選打開連結 ,翻譯有出入之處,請以原文為準

本文中,我們讨論一個問題:如何計算(或者說,估算)一個Java對象占用的記憶體數量?

通常,我們談論的堆記憶體使用的前提是以“一般情況”為背景的。不包括下面兩種情形:

  1. 某些情況下,JVM根本就沒有把Object放入堆中。例如:原則上講,一個小的thread-local對象存在于棧中,而不是在堆中。
  2. 被Object占用記憶體的大小依賴于Object的目前狀态。例如:Object的同步鎖是否生效,或者,Object是否正在被回收。

我們先來看看在堆中單個的Object長什麼樣子

JAVA記憶體使用--如何計算一個Java對象占用的位元組數

在堆中,每個對象由四個域構成(A、B、C 和 D),下面我們逐個解釋一下:

  1. A:對象頭,占用很少的位元組,表述Object目前狀态的資訊
  2. B:基本類型域占用的空間(原生域指 int、boolean、short等)
  3. C:引用類型域占用的空間(引用類型域指 其他對象的引用,每個引用占用4個位元組)
  4. D:填充物占用的空間(後面說明什麼是填充物)

下面我們對A、B、C 和 D 逐一解釋

A:對象頭

記憶體中,每個對象占用的總空間不僅包含對象内聲明的變量所需要的空間,還包括一些額外資訊,比如:對象頭 和 填充物。“對象頭”的作用是用來記錄一個對象的執行個體名字、ID 和 執行個體狀态(例如,目前執行個體是否“可到達”,或者目前鎖的狀态等等)。

在目前的JVM版本中(Hotspot),“對象頭”占用的位元組數如下:

  1. 一個普通對象,占用8 bytes
  2. 數組,占用 12 bytes,包含普通對象的 8 bytes + 4 bytes(數組長度)

B:基本類型

boolean、byte 占用 1 byte,char、short 占用 2 bytes,int、float 占用 4 bytes,long、double 占用 8 bytes

C:引用類型

每個引用類型占用 4 bytes

D:填充物

在Hotspot中,每個對象占用的總空間是以8的倍數計算的,對象占用總空間(對象頭+聲明變量)不足8的倍數時候,自動補齊。而,這些被填充的空間,我們可以稱它為“填充物”。我們看下具體執行個體:

  1. 一個空對象(沒有聲明任何變量)占用 8 bytes -- > 對象頭 占用 8 bytes
  2. 隻聲明了一個boolean類型變量的類,占用 16 bytes --> 對象頭(8 bytes) + boolean (1 bytes) + 填充物(7 bytes)
  3. 聲明了8個boolean類型變量的類,占用 16 bytes --> 對象頭(8 bytes) + boolean (1 bytes) * 8

通過上面的執行個體,更有助于我們了解