Shallow Size和Retained Size詳解

Shallow Size和Retained Size詳解

參考文章
How much memory do I need (part 1) – What is retained heap?

How much memory do I need (part 2) – What is shallow heap?

在Android開發中, 想要進行內存分析, 總會看見Shallow SizeRetained Size, 這邊文章主要解釋

  1. 它們分別表示什麼含義
  2. 它們是如何計算出來的

Java garbage collection (GC)

我們先了解GC的一些基本知識

  1. 程序中存在一些實例, 稱作GC root, 它們不會被GC回收, 常見的例如靜態變量, 線程等
  2. GC root直接或間接引用的實例會被標記爲in use, 它們也不會被GC回收

Shallow Size

Shallow Size是指實例自身佔用的內存, 可以理解爲保存該'數據結構'需要多少內存, 注意不包括它引用的其他實例

計算公式:

Shallow Size = [類定義] + 父類fields所佔空間 + 自身fields所佔空間 + [alignment]
  1. 類定義是指, 聲明一個類本身所需的空間, 固定爲8byte, 也就是說, 一個不包含任何fields的類的'空類', 也需要佔8byte; 另外類定義空間不會重複計算, 就是說, 即使類繼承其他類, 也只算8byte
  2. 父類fields所佔空間, 對於繼承了其他類的類來說, 父類聲明的fields顯然需要佔用一定的空間
  3. 自身fields所佔空間, 所有fields所佔空間之和; fields分基本類型和引用, 基本類型所佔空間和系統有關, 例如在32位系統中int=4byte, 64位系統中int=8byte; 引用固定佔4byte, 例如String name;這個變量聲明佔4byte.
  4. alignment是指位數對齊, 會讓總空間爲8的倍數, 例如某個A類, 以上3項計算出來爲15byte, 那麼爲了對齊, 讓它是8的倍數, 會取最接近的值, 所以它的Shallow Size是16byte;

注意, alignment行爲和JVM有關, 對於Android來說, 實測4.4系統會有對齊行爲, 但是5.1系統不會

Shallow Size例子

class X {
    int a;
    byte b;
    Integer c = new Integer();
}

假設當前是在32位系統, 對於類X來說, 一個X實例的Shallow Size爲:

  1. 類定義的8byte
  2. 沒有繼承其他類, 所以沒有父類fields
  3. a變量爲int型, 4byte; b變量爲byte型, 1byte; c變量是引用類型, 和它是否指向具體實例無關, 固定佔4byte

如果不算alignment,

X的Shallow Size = 8 + 0 + 4 + 1 + 4 = 17byte

如果算上alignment, 那麼要補齊爲8的倍數, 也就是24byte.

class Y extends X {
    List d;
    Date e;
}

一個Y實例的Shallow Size爲:

  1. 類定義的8byte
  2. 繼承了X類, X類的所有fields爲X類的Shallow Size減去類定義空間8byte, 也就是17byte-8byte=9byte
  3. d, e都是引用類型, 各佔4byte

如果不算alignment,

Y的Shallow Size = 8 + 9 + 4 + 4 = 25byte

如果算上alignment, 那麼要補齊爲8的倍數, 也就是32byte.

Retained Size

實例A的Retained Size是指, 當實例A被回收時, 可以同時被回收的實例的Shallow Size之和

所以進行內存分析時, 我們應該重點關注Retained Size較大的實例; 或者可以通過Retained Size判斷出某A實例內部使用的實例是否被其他實例引用.
例如在Android中, 如果某個Bitmap實例的Retained Size很小, 證明它內部的byte數組被複用了, 有另一個Bitmap實例指向了同一個byte數組.

Retained Size例子

圖中A, B, C, D四個實例, 爲了方便計算, 我們假設所有實例的Shallow Size都是1kb

D實例

D實例沒有引用其他實例, 所以移除D實例只會釋放它自己的空間, 因此

D實例的Retained Size=Shallow Size=1kb

C實例

當我們移除C實例, C實例引用了D實例, 同時D實例沒有被其他實例引用, 所以D實例也會被GC, 所以

C實例的Retained Size = C實例的Shallow Size + D實例的Shallow Size = 2kb

B實例

當我們移除B實例, 雖然B實例引用了C實例, 但是A實例也引用了C實例, 所以移除B實例不會讓C實例被GC, 所以

B實例的Retained Size=Shallow Size=1kb

A實例

當我們移除A實例, 顯然A, B, C, D實例都會被GC, 所以

A實例的Retained Size=4kb

總結

計算Retained Size的關鍵在於領會移除實例時, 可以同時被回收的實例, 重點觀察B實例的情況

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章