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開(kāi)發(fā)中, 想要進(jìn)行內(nèi)存分析, 總會(huì)看見(jiàn)Shallow SizeRetained Size, 這邊文章主要解釋

  1. 它們分別表示什么含義
  2. 它們是如何計(jì)算出來(lái)的

Java garbage collection (GC)

我們先了解GC的一些基本知識(shí)

  1. 程序中存在一些實(shí)例, 稱(chēng)作GC root, 它們不會(huì)被GC回收, 常見(jiàn)的例如靜態(tài)變量, 線程等
  2. GC root直接或間接引用的實(shí)例會(huì)被標(biāo)記為in use, 它們也不會(huì)被GC回收

Shallow Size

Shallow Size是指實(shí)例自身占用的內(nèi)存, 可以理解為保存該'數(shù)據(jù)結(jié)構(gòu)'需要多少內(nèi)存, 注意不包括它引用的其他實(shí)例

計(jì)算公式:

Shallow Size = [類(lèi)定義] + 父類(lèi)fields所占空間 + 自身fields所占空間 + [alignment]
  1. 類(lèi)定義是指, 聲明一個(gè)類(lèi)本身所需的空間, 固定為8byte, 也就是說(shuō), 一個(gè)不包含任何fields的類(lèi)的'空類(lèi)', 也需要占8byte; 另外類(lèi)定義空間不會(huì)重復(fù)計(jì)算, 就是說(shuō), 即使類(lèi)繼承其他類(lèi), 也只算8byte
  2. 父類(lèi)fields所占空間, 對(duì)于繼承了其他類(lèi)的類(lèi)來(lái)說(shuō), 父類(lèi)聲明的fields顯然需要占用一定的空間
  3. 自身fields所占空間, 所有fields所占空間之和; fields分基本類(lèi)型和引用, 基本類(lèi)型所占空間和系統(tǒng)有關(guān), 例如在32位系統(tǒng)中int=4byte, 64位系統(tǒng)中int=8byte; 引用固定占4byte, 例如String name;這個(gè)變量聲明占4byte.
  4. alignment是指位數(shù)對(duì)齊, 會(huì)讓總空間為8的倍數(shù), 例如某個(gè)A類(lèi), 以上3項(xiàng)計(jì)算出來(lái)為15byte, 那么為了對(duì)齊, 讓它是8的倍數(shù), 會(huì)取最接近的值, 所以它的Shallow Size是16byte;

注意, alignment行為和JVM有關(guān), 對(duì)于Android來(lái)說(shuō), 實(shí)測(cè)4.4系統(tǒng)會(huì)有對(duì)齊行為, 但是5.1系統(tǒng)不會(huì)

Shallow Size例子

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

假設(shè)當(dāng)前是在32位系統(tǒng), 對(duì)于類(lèi)X來(lái)說(shuō), 一個(gè)X實(shí)例的Shallow Size為:

  1. 類(lèi)定義的8byte
  2. 沒(méi)有繼承其他類(lèi), 所以沒(méi)有父類(lèi)fields
  3. a變量為int型, 4byte; b變量為byte型, 1byte; c變量是引用類(lèi)型, 和它是否指向具體實(shí)例無(wú)關(guān), 固定占4byte

如果不算alignment,

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

如果算上alignment, 那么要補(bǔ)齊為8的倍數(shù), 也就是24byte.

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

一個(gè)Y實(shí)例的Shallow Size為:

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

如果不算alignment,

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

如果算上alignment, 那么要補(bǔ)齊為8的倍數(shù), 也就是32byte.

Retained Size

實(shí)例A的Retained Size是指, 當(dāng)實(shí)例A被回收時(shí), 可以同時(shí)被回收的實(shí)例的Shallow Size之和

所以進(jìn)行內(nèi)存分析時(shí), 我們應(yīng)該重點(diǎn)關(guān)注Retained Size較大的實(shí)例; 或者可以通過(guò)Retained Size判斷出某A實(shí)例內(nèi)部使用的實(shí)例是否被其他實(shí)例引用.
例如在Android中, 如果某個(gè)Bitmap實(shí)例的Retained Size很小, 證明它內(nèi)部的byte數(shù)組被復(fù)用了, 有另一個(gè)Bitmap實(shí)例指向了同一個(gè)byte數(shù)組.

Retained Size例子

RetainedSize例子.png

圖中A, B, C, D四個(gè)實(shí)例, 為了方便計(jì)算, 我們假設(shè)所有實(shí)例的Shallow Size都是1kb

D實(shí)例

D實(shí)例沒(méi)有引用其他實(shí)例, 所以移除D實(shí)例只會(huì)釋放它自己的空間, 因此

D實(shí)例的Retained Size=Shallow Size=1kb

C實(shí)例

當(dāng)我們移除C實(shí)例, C實(shí)例引用了D實(shí)例, 同時(shí)D實(shí)例沒(méi)有被其他實(shí)例引用, 所以D實(shí)例也會(huì)被GC, 所以

C實(shí)例的Retained Size = C實(shí)例的Shallow Size + D實(shí)例的Shallow Size = 2kb

B實(shí)例

當(dāng)我們移除B實(shí)例, 雖然B實(shí)例引用了C實(shí)例, 但是A實(shí)例也引用了C實(shí)例, 所以移除B實(shí)例不會(huì)讓C實(shí)例被GC, 所以

B實(shí)例的Retained Size=Shallow Size=1kb

A實(shí)例

當(dāng)我們移除A實(shí)例, 顯然A, B, C, D實(shí)例都會(huì)被GC, 所以

A實(shí)例的Retained Size=4kb

總結(jié)

計(jì)算Retained Size的關(guān)鍵在于領(lǐng)會(huì)移除實(shí)例時(shí), 可以同時(shí)被回收的實(shí)例, 重點(diǎn)觀察B實(shí)例的情況

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容