記憶體優化相關

檸檬茶就是力量發表於2019-07-23

總結一些比較日常的記憶體優化策略

  • 用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不太適合資料量比較大的場景。

image.png

  • 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";    
}   
複製程式碼

相關文章