調皮的記憶體抖動?前生今世及App解決卡頓慢

codeGoogle發表於2019-02-27

記憶體抖動

·記憶體抖動是指記憶體頻繁地分配和回收,而頻繁的gc會導致卡頓,嚴重時和記憶體洩漏一樣會導致OOM。

注意記憶體抖動為什麼會造成OOM這關係到Java的垃圾回收。

造成的原因

主要是頻繁(很重要)在迴圈裡建立物件

  • 1、導致大量物件在短時間內被建立,由於新物件是要佔用記憶體空間的而且是頻繁,如果一次或者兩次在迴圈裡建立物件對記憶體影響不大,不會造成嚴重記憶體抖動這樣可以接受也不可避免

  • 2、頻繁的話就很記憶體抖動很嚴重

簡單的提一下垃圾回收機制

垃圾回收

在對物件進行回收前需要對垃圾進行採集,不同的虛擬機器實現可能使用不同的垃圾收集演算法,不同的收集演算法的實現也不盡相同。不同的演算法各有各的優劣勢。

常用的收集演算法有:

1、標記-清除演算法 Mark-Sweep

調皮的記憶體抖動?前生今世及App解決卡頓慢

和他的名字一樣,演算法分為標記和清除兩個階段:首先標記出所有需要回收的物件,在標記完成後統一回收被標記的物件。

2、複製演算法 Copying

“複製”(Copying)的收集演算法,它將可用記憶體按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當這一塊的記憶體用完了,就將還存活著的物件複製到另外一塊上面,然後再把已使用過的記憶體空間一次清理掉。

3、標記壓縮演算法 Mark-Compact

調皮的記憶體抖動?前生今世及App解決卡頓慢

記憶體抖動為什麼會造成 OOM?

首先我們要了解一些垃圾回收機制的前因後果

在對物件進行回收前需要對垃圾進行採集,不同的虛擬機器實現可能使用不同的垃圾收集演算法,不同的收集演算法的實現也不盡相同。不同的演算法各有各的優劣勢。

常用的收集演算法有:

1、標記-清除演算法 Mark-Sweep 2、複製演算法 Copying 3、標記壓縮演算法 Mark-Compact

無論是一般的JVM還是DVM,不會只使用一種垃圾收集演算法。它會根據記憶體的劃分實現不同的收集演算法。

當前商業虛擬機器的垃圾收集都採用分代收集演算法。分代的垃圾回收策略,是基於不同的物件的生命週期是不一樣的。因此,不同生命週期的物件可以採取不同的收集方式,以便提高回收效率。

在Java程式執行的過程中,會產生大量的物件,因每個物件所能承擔的職責不同所具有的功能不同所以也有著不一樣的生命週期,有的物件生命週期較長,比如Android中的Application、啟動的Service等;有的物件生命週期較短,比如一些函式內部new出來的String物件。

在不進行物件存活時間區分的情況下,每次垃圾回收都是對整個堆空間進行回收,那麼消耗的時間相對會很長,而且對於存活時間較長的物件進行的掃描工作等都是徒勞。因此就需要引入分治的思想,所謂分治的思想就是因地制宜,將物件進行代的劃分,把不同生命週期的物件放在不同的代上使用不同的垃圾回收方式。

現在主流的做法是將Java堆被分為

  • 1、新生代
  • 2、老年代;

新生代又被進一步劃分為Eden和Survivor區, Survivor由From Space和To Space組成

這樣劃分的好處是為了更快的回收記憶體,根據不同的分代執行不同的回收演算法;

調皮的記憶體抖動?前生今世及App解決卡頓慢

Android 虛擬機器的由來

Java 虛擬機器是一個規範,任何實現該規範的虛擬機器都可以用來執行 Java 程式碼。android就是覺得現在使用的jvm用著不爽,由於 Androd 執行在移動裝置上,記憶體以及電量等諸多方面跟一般的 PC 裝置都有本質的區別 ,一般的 JVM 沒法滿足移動裝置的要求,所以自己根據這個規範開發了一個Dalvik 虛擬機器。

Dalvik虛擬機器主要使用標記清除演算法,也可以選擇使用拷貝演算法。這取決於編譯時期:

ART 是在 Android 4.4 中引入的一個開發者選項,也是 Android 5.0 及更高版本的預設 Android 執行時。google已不再繼續維護和提供 Dalvik 執行時,現在 ART 採用了其位元組碼格式。

ART 有多個不同的 GC 方案,這些方案包括執行不同垃圾回收器。預設方案是 CMS。
複製程式碼

這就是記憶體抖動為什麼會造成 Android App OOM。

檢測優化記憶體抖動

記憶體抖動在Android Profile中表現為:

記憶體抖動在Android Profile中表現

關於記憶體抖動和記憶體洩漏就到這裡了,接下來就說一下Android studio 提供的記憶體優化方面的工具

**1、利用Alloctions Tracker來進行排查。**前提AndroidStudio版本>=3.0, 在Android Studio中點選memory profiler中的紅點錄製一段時間的記憶體申請情況,再點選結束。 Android Studio提供了工具來幫助開發者發現和解決記憶體抖動和記憶體洩漏。

2、 Tool - Memory Monitor(用於發現記憶體抖動及記憶體洩漏的)

Android Studio中的Memory Monitor可以很好的幫組我們檢視程式的記憶體使用情況。 Memory Monitor:檢視整個app所佔用的記憶體,以及發生GC的時刻,短時間內發生大量的GC操作是一個危險的訊號(用於發現有沒有記憶體洩漏和嚴重記憶體抖動)。

(後面兩個是用於定位的記憶體抖動和記憶體洩漏發生的具體位置·) Allocation Tracker:使用此工具來追蹤記憶體的分配,前面有提到過。

Heap Tool:檢視當前記憶體快照,便於對比分析哪些物件有可能是洩漏了的.

舉個栗子

你需要避免在for迴圈裡面分配物件佔用記憶體,需要嘗試把物件的建立移到迴圈體之外,自定義View中的onDraw方法也需要引起注意,每次螢幕發生繪製以及動畫執行過程中,onDraw方法都會被呼叫到,避免在onDraw方法裡面執行復雜的操作,避免建立物件。對於那些無法避免需要建立物件的情況,我們可以考慮物件池模型,通過物件池來解決頻繁建立與銷燬的問題,但是這裡需要注意結束使用之後,需要手動釋放物件池中的物件。

下面是避免發生記憶體抖動的幾點建議:

  • 儘量避免在迴圈體或者頻繁呼叫的函式內建立物件,應該把物件建立移到迴圈體外。
  • 注意自定義View的onDraw()方法會被頻繁呼叫,所以在這裡面不應該頻繁的建立物件。
  • 當需要大量使用Bitmap的時候,試著把它們快取在陣列中實現複用。
  • 對於能夠複用的物件,同理可以使用物件池將它們快取起來。

更多閱讀

Android效能優化 (1)—— 記憶體溢位和記憶體洩漏的介紹

淺談App的效能優化

Android效能優化之包體壓縮,一篇文章教你玩轉優化App

BlockCannery-一個強大的Android程式除錯工具,輕鬆幫你找出卡頓

相信自己,沒有做不到的,只有想不到的

微信公眾號:終端研發部

技術

相關文章