Android 中的 Enum 到底占多少內存?該如何用?

Zul99T 8年前發布 | 18K 次閱讀 Android enum Android開發 移動開發

聽說過一些論調,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/

 本文由用戶 Zul99T 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!