總結一些比較日常的記憶體優化策略
-
用SparseArray / ArrayMap 代替HashMap
SparseArray:
如果key的型別已經確定為int型別,那麼使用SparseArray,因為它避免了自動裝箱的過程,如果key為long型別,它還提供了一個
LongSparseArray
來確保key為long型別時的使用,如果key型別為其它的型別,則使用ArrayMap
ArrayMap:
android.util.ArrayMap儲存結構是由int[] mHashes和Object[] mArray兩個資料組成,mHashes儲存key的hashCode,mArray以鍵值對形式儲存key和value。 ArrayMap取資料時通過二分法查詢index,獲取相應value。 ArrayMap在remove和clear後,會重新收縮資料,節約空間,但會降低執行效率。ArrayMap是犧牲了時間換取空間。根據官方描述,由於查詢方式採用的是二分法,並且當你刪除或者新增資料時,會對空間重新調整,ArrayMap不太適合資料量比較大的場景。
-
Enum (列舉)
避免使用列舉,用靜態變數代替,列舉佔用的內容大的多
-
減少 Bitmap 物件的記憶體佔用
Bitmap是一個極容易消耗記憶體的大胖子,減小建立出來的Bitmap的記憶體佔用是很重要的,通常來說有下面2個措施:
1.inSampleSize:縮放比例,在把圖片載入記憶體之前,我們需要先計算出一個合適的縮放比例,避免不必要的大圖載入。
2.decode format:解碼格式,選擇 ARGB_8888 / RBG_565/ ARGB_4444 / ALPHA_8,這幾種格式存在很大差異和記憶體佔用情況。
-
注意臨時 Bitmap 物件的及時回收
我們會對 Bitmap 增加快取機制,但是在某些時候,部分 Bitmap 是需要及時回收的。例如臨時建立的某個相對比較大的 Bitmap 物件,在經過變換得到新的 Bitmap 物件之後,應該儘快回收原始的 Bitmap,這樣能夠更快釋放原始 Bitmap 所佔用的空間。 需要特別留意的是 Bitmap 類裡面提供的
createBitmap()
方法: 這個函式返回的 Bitmap 有可能和 source bitmap 是同一個,在回收的時候,需要特別檢查 source bitmap 與 return bitmap 的引用是否相同,只有在不等的情況下,才能夠執行 source bitmap 的 recycle() 方法
-
儘量地採用 int 型別
Android 系統中 float 型別的資料存取速度是 int 型別的一半,儘量優先採用 int 型別。而同樣能作為整數的代名詞,採用 int 替換 Integer 會讓你的記憶體開銷更小。
- 適當使用intern
JDK7以及以後String類提供了
intern()
方法,手動呼叫可以把物件放到常量池中,後續呼叫的時候如果在常量池中匹配到了就直接使用,避免重複建立物件,但是使用了intern()
之後會相當於花費多一點點時間,但是資料多的情況下,花費的那點時間和節省下來的空間來說還是不值一提的
-
儘量使用原字串的 subString
當從已經存在的資料集中抽取出 String 的時候,嘗試返回原資料的
subString
物件,而不要建立一個重複的物件。這一點比較少見,因為每次呼叫subString
方法都會建立一個新的String物件
-
避免在頻繁呼叫的方法比如 onDraw() 裡面執行物件的建立
類似 onDraw() 等頻繁呼叫的方法,一定需要注意避免在這裡做建立物件的操作,因為他會迅速增加記憶體的使用,而且很容易引起頻繁的 gc,甚至是記憶體抖動。
-
迴圈裡操作字串的時候改用
StringBuffer
/StringBuilder
來操作
如果直接在迴圈裡用
+
拼接字串,會建立很多無用的物件,比如說以下程式碼在每次迴圈的時候都會建立了新的StringBuilder
物件,所以這種情況可以在外部建立一個StringBuilder
物件,在迴圈內呼叫append
方法
for(int i = 0; i < 100; i++) {
s += "a";
}
複製程式碼