Android 中的 Enum 到底占多少內存?該如何用?
聽說過一些論調,Enum 不該用啊,占用了很大的 dex 文件,占用很多內存。而到底確切占用了多少內存,沒說。本文分析了枚舉所占用的精確的內存大小,方便大家權衡選擇,希望對大家有幫助。
關于 Enum 的使用
Enum
需要占用較大的內存,如果對內存敏感,請盡量少使用 Enum
,換用做靜態常量。
文檔 提到:
Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android.
關于具體要占用多少內存呢?說得比較模糊。
內存占用對比
我 在 《Dalvik 中的對象大小》一文中, 介紹過如何衡量對象的大小,這個文章非常詳細,建議大家看看 ,現舉例說明。
public enum MonthEnum {
// 4 bytes
JANUARY, // -> 87 bytes
// 4 bytes
FEBRUARY // -> 88 bytes
// 生成的數組 24 + 4 + 4
// MonthEnum[] values
}
public class MonthConst {
// 4 bytes
public static final int JANUARY = 1;
// 4 bytes
public static final int FEBRUARY = 2;
}
public class UseMonth {
// 4 bytes
private int mMonth = MonthConst.JANUARY;
// 4 bytes
private MonthEnum mMonthEnum = MonthEnum.JANUARY;
}
</code></pre>
我們不考慮 MonthEnum
和 MonthConst
他們對于 dex 大小的影響,這個沒什么意義,幾十個 Enum
占用的大小,也不及一張圖片。
我們要對比的是 UseMonth
中這兩種寫法所占用的內存大小在 Dalvik 虛擬機下的區別。
在 UseMonth
中,他們一個是 int
類型,一個是對象引用,都是 4 字節,沒有區別。
我們對比的大小,指的是對象本身的大小加上對象成員指向的其他對象大小,即 shadow heap + maintain heap。
-
MonthEnum
對于一個 MonthEnum
, JANUARY
和 FEBRUARY
是兩個指向 MonthEnum
實例的引用。他們分別占用 4 個字節。
他們指向的實例對象還要占用額外的內存。
我們看看 enum
的定義:
class Enum {
private final String name;
private final int ordinal;
}
作為 Enum
成員變量 name
(對象引用) 和 ordinal
(int) 他們各占用 4 個字節,該對象實例占用:12 + 4 + 4 = 20 bytes,對齊之后是 24 字節。
但是,name
是字符串,空字符串對象本身就是 32 字節,加上其中的字符數組最少也會占據 24 個字節, 對字符串加字符數組最少會占據 56 個字節。故一個 Enum
實例,最少 80 個字節。
MonthEnum.JANUARY
,含有 7 個字符,87 個字節;MonthEnum.FEBRUARY
,8 個字符,88 個字節。
枚舉編譯完之后 會有一個 values()
數組,兩個對象引用的數組占用: 24 + 4 + 4 = 32 bytes。
總計是: 4 + 4 + 87 + 88 + 32
-
MonthConst
JANUARY
和 FEBRUARY
各占 4 個字節。共計 8 個字節。
總計是: 4 + 4
上面我們對比了只具有兩個枚舉值的枚舉和常量,如果數量更多的話,枚舉的命名更長的話,這個差距會更大。
文檔所說的兩倍
所以實際占用的內存,并非 文檔 所說的兩倍左右。
假設有 n 個枚舉值,僅僅考慮枚舉類,靜態占用的內存,n 個引用 + n 個數組 + 24 空數組長度: 8n + 24。
而對于 n 個值的常量,則有 4n 字節。當 n 很大時,這樣的關系是兩倍,但是枚舉引用所指向的內存(retained heap)沒有考慮進來。
該用不該用?
文檔 提到:
You should strictly avoid using enums on Android.
枚舉有其其他的特性,如果你需要這些特性,比如:非連續數值的判斷,重載等時,可以用。
另外,內存用量也并非那么地可怕,枚舉帶來的編碼的便捷,代碼可讀性的提升也是很大的利好。
看到這里,你應該了解了所有的細節了,是否該用,各位自己權衡。
更多的討論,可以看這里: 該不該用枚舉。
如果更好地使用常量
如果應用確實對內存用量敏感,或者你就是追求極致,可用常量來代替枚舉。
常量一般會和 Bit Mask 結合起來用,這樣可以極致地減少了內存使用,同時使代碼有較好的可讀性。
下一篇文章會提到。
來自:http://www.liaohuqiu.net/cn/posts/android-enum-memory-usage/