Android App解決卡頓慢之記憶體抖動及記憶體流失(發現和定位)

來源:互聯網
上載者:User

標籤:led   應該   heap   內容   draw   不能   繪製   mon   調用   

記憶體抖動是指在短時間內有大量的對象被建立或者被回收的現象,記憶體抖動出現原因主要是頻繁(很重要)在迴圈裡建立對象(導致大量對象在短時間內被建立,由於新對象是要佔用記憶體空間的而且是頻繁,如果一次或者兩次在迴圈裡建立對象對記憶體影響不大,不會造成嚴重記憶體抖動這樣可以接受也不可避免,頻繁的話就很記憶體抖動很嚴重),記憶體抖動的影響是如果抖動很頻繁,會導致記憶體回收機制頻繁運行(短時間內產生大量對象,需要大量記憶體,而且還是頻繁抖動,就可能會需要回收記憶體以用於產生對象,記憶體回收機制就自然會頻繁運行了)。綜上就是頻繁記憶體抖動會導致記憶體回收頻繁運行。

記憶體流失是指某一段記憶體在程式裡功能上已經不需要了,但是記憶體回收機制回收記憶體時檢測那段記憶體還是被需要的,不能被回收,這種在程式中在沒有使用的但是又不能被回收的記憶體就是被泄漏的記憶體,那為什麼會這樣呢?正常的話應該是程式裡不需要的記憶體就可以被回收,這是記憶體回收機製做的事呀,如果記憶體回收機制正常啟動並執行情況下,不應該這樣啊,但是實際就是記憶體回收機制正常的情況下發生的記憶體流失。其實到這裡java程式員就得知道記憶體回收機制中,判斷一段記憶體是否是垃圾,是否可回收的條件,這個條件是通過檢查這段記憶體是否存在引用和被參考關聯性,不存在這關係時,就認為可回收,若還存在引用或被參考關聯性,就認為不可回收,現在就可以知道導致記憶體流失的原因是程式員沒有將不用的記憶體去掉參考關聯性(因為程式中大多記憶體石油對象指向的,所以去掉參考關聯性就是置空)。記憶體流失會導致一些記憶體沒法被正常利用,話句話就是可以使用記憶體變少了,這樣輕則增加記憶體回收機制運行頻率,重則記憶體溢出(當系統需要分配一段記憶體,但是現有記憶體在記憶體回收運行後任然不足時,就會記憶體溢出);為避免記憶體流失,在寫程式時已經確定不需要的引用型變數,就置空;雖然即使記憶體沒泄露,也有可能出現記憶體溢出,這時的記憶體溢出就是有別的問題導致的。

 

1) Memory Churn and performance(記憶體抖動和效能)

雖然Android有自動管理記憶體的機制,但是對記憶體的不恰當使用仍然容易引起嚴重的效能問題。在同一幀裡面建立過多的對象是件需要特別引起注意的事情。

Android系統裡面有一個Generational Heap Memory的模型,系統會根據記憶體中不同的記憶體資料類型分別執行不同的GC操作。例如,最近剛分配的對象會放在Young Generation地區,這個地區的對象通常都是會快速被建立並且很快被銷毀回收的,同時這個地區的GC操作速度也是比Old Generation地區的GC操作速度更快的。

 

除了速度差異之外,執行GC操作的時候,任何線程的任何操作都會需要暫停,等待GC操作完成之後,其他動作才能夠繼續運行(所以記憶體回收啟動並執行次數越少,對效能的影響就越少)。

 

通常來說,單個的GC並不會佔用太多時間,但是大量不停的GC操作則會顯著佔用幀間隔時間(16ms)。如果在幀間隔時間裡面做了過多的GC操作,那麼自然其他類似計算,渲染等操作的可用時間就變得少了。

導致GC頻繁執行有兩個原因:

·Memory Churn記憶體抖動,記憶體抖動是因為大量的對象被建立又在短時間內馬上被釋放。

·瞬間產生大量的對象會嚴重佔用Young Generation的記憶體地區,當達到閥值,剩餘空間不夠的時候,也會觸發GC。即使每次分配的對象佔用了很少的記憶體,但是他們疊加在一起會增加Heap的壓力,從而觸發更多其他類型的GC。這個操作有可能會影響到幀率,並使得使用者感知到效能問題(幀率是Android渲染機制中的概念,導致卡頓慢的直接原因,就是渲染機制受阻,關於渲染機制有另一篇部落格特別說了,想瞭解的可以點擊這裡)。

 

解決上面的問題有簡潔直觀方法,如果你在Memory Monitor裡面查看到短時間發生了多次記憶體的漲跌,這意味著很有可能發生了記憶體抖動。

 

同時我們還可以通過Allocation Tracker來查看在短時間內,同一個棧中不斷進出的相同對象。這是記憶體抖動的典型訊號之一。

當你大致定位問題之後,接下去的問題修複也就顯得相對直接簡單了。例如,你需要避免在for迴圈裡面指派至佔用記憶體,需要嘗試把對象的建立移到迴圈體之外,自訂View中的onDraw方法也需要引起注意,每次螢幕發生繪製以及動畫執行過程中,onDraw方法都會被調用到,避免在onDraw方法裡面執行複雜的操作,避免建立對象。對於那些無法避免需要建立對象的情況,我們可以考慮對象池模型,通過對象池來解決頻繁建立與銷毀的問題,但是這裡需要注意結束使用之後,需要手動釋放對象池中的對象。

2) Garbage Collection in Android(Android記憶體回收)

JVM的回收機制給開發人員帶來很大的好處,不用時刻處理對象的分配與回收,可以更加專註於更加進階的代碼實現。相比起Java,C與C++等語言具備更高的執行效率,他們需要開發人員自己關注對象的分配與回收,但是在一個龐大的系統當中,還是免不了經常發生部分對象忘記回收的情況,這就是記憶體流失。

原始JVM中的GC機制在Android中得到了很大程度上的最佳化。Android裡面是一個三級Generation的記憶體模型,最近分配的對象會存放在Young Generation地區,當這個對象在這個地區停留的時間達到一定程度,它會被移動到Old Generation,最後到Permanent Generation地區。

 

每一個層級的記憶體地區都有固定的大小,此後不斷有新的對象被分配到此地區,當這些對象總的大小快達到這一層級記憶體地區的閥值時,會觸發GC的操作,以便騰出空間來存放其他新的對象。

 

前面提到過每次GC發生的時候,所有的線程都是暫停狀態的。GC所佔用的時間和它是哪一個Generation也有關係,Young Generation的每次GC操作時間是最短的,Old Generation其次,Permanent Generation最長。執行時間的長短也和當前Generation中的對象數量有關,遍曆尋找20000個對象比起遍曆50個對象自然是要慢很多的。

雖然Google的工程師在盡量縮短每次GC所花費的時間,但是特別注意GC引起的效能問題還是很有必要。如果不小心在最小的for迴圈單元裡面執行了建立對象的操作,這將很容易引起GC並導致效能問題。通過Memory Monitor我們可以查看到記憶體的佔用情況,每一次瞬間的記憶體降低都是因為此時發生了GC操作,如果在短時間內發生大量的記憶體上漲與降低的事件(記憶體嚴重抖動),這說明很有可能這裡有效能問題。我們還可以通過Heap and Allocation Tracker工具來查看此時記憶體中分配的到底有哪些對象。

到這裡為止就簡單介紹了記憶體抖動(概念及判斷方法,方法是兩個工具使用,一個用於判斷有沒有嚴重記憶體抖動Memory Monitor,一個用於確認抖動位置Heap and Allocation Tracker),及較詳細的介紹了Android中記憶體回收機制。

 

2) Performance Cost of Memory Leaks(記憶體流失)

雖然Java有自動回收的機制,可是這不意味著Java中不存在記憶體流失的問題,而記憶體流失會很容易導致嚴重的效能問題。

記憶體流失指的是那些程式不再使用的對象無法被GC識別,這樣就導致這個對象一直留在記憶體當中,佔用了寶貴的記憶體空間。顯然,這還使得每級Generation的記憶體地區可用空間變小,GC就會更容易被觸發,從而引起效能問題。

尋找記憶體流失並修複這個漏洞是件很棘手的事情,你需要對執行的代碼很熟悉,清楚的知道在特定環境下是如何啟動並執行,然後仔細排查。例如,你想知道程式中的某個activity退出的時候,它之前所佔用的記憶體是否有完整的釋放乾淨了?首先你需要在activity處於前台的時候使用Heap Tool擷取一份目前狀態的記憶體快照,然後你需要建立一個幾乎不這麼佔用記憶體的空白activity用來給前一個Activity進行跳轉,其次在跳轉到這個空白的activity的時候主動調用System.gc()方法來確保觸發一個GC操作。最後,如果前面這個activity的記憶體都有全部正確釋放,那麼在空白activity被啟動之後的記憶體快照中應該不會有前面那個activity中的任何對象了。


 

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

 

 

Android Studio提供了工具來協助開發人員發現和解決記憶體抖動和記憶體流失。

 

 Tool - Memory Monitor(用於發現記憶體抖動及記憶體流失的)

Android Studio中的Memory Monitor可以很好的幫組我們查看程式的記憶體使用量情況。

 

 


以下內容很重要,以下內容很重要,以下內容很重要重要的事情說三遍

·Memory Monitor:查看整個app所佔用的記憶體,以及發生GC的時刻,短時間內發生大量的GC操作是一個危險的訊號(用於發現有沒有記憶體流失和嚴重記憶體抖動)。

後面兩個是用於定位的記憶體抖動和記憶體流失發生的具體位置·

Allocation Tracker:使用此工具來追蹤記憶體的分配,前面有提到過。

Heap Tool:查看當前記憶體快照,便於對比分析哪些對象有可能是泄漏了的.

  現在就可以定位到某一段代碼發生了記憶體流失或抖動。

如果是記憶體流失解決方案就很直接,在適當的時候把泄漏的對象置空就可以了。

但是如果只記憶體抖動的話就得分兩種情況,由於記憶體抖動是在短時間內建立釋放大量對象導致的(一般是迴圈內建立對象),直接辦法就是不再短時間內建立大量對象,如果建立對象的過程可以拿到迴圈外而不影響功能,這種情況比較容易解決。但是更多的是另一種情況,就是不能拿到迴圈外,否則影響功能。對於第二種情況就要做到再迴圈內建立對象,但是又要控制對象個數。這種情況還是下一篇在說明解決辦法。

.

Android App解決卡頓慢之記憶體抖動及記憶體流失(發現和定位)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.