Android性能優化之內存優化

語言: CN / TW / HK

本文正在參加「金石計劃」

Android內存優化是一項重要的任務,因為內存是Android系統中最關鍵的資源之一。寫出一個app容易,寫好一個app不容易,因為要做大量的優化,並且是持續的優化。關於內存優化,我們需要了解哪些知識呢?什麼是內存泄漏?如何檢測內存泄漏?什麼是OOM內存溢出?如何使用Android Studio自帶的內存分析工具?帶着這幾個問題我們就進入了正題。

什麼是內存泄漏

內存泄漏是指在計算機程序中,分配的內存空間沒有被正確釋放或回收的情況。這種情況會導致程序佔用越來越多的內存,直到最終程序崩潰或系統資源不足。

內存泄漏不是我們Android特有的,C/C++語言寫的程序也會內存泄漏,我們Java中的內存泄漏相對來説比較容易發現和解決。Java的內存泄漏發生在強引用中,Java的引用總共有4種,強引用、軟引用、弱引用和虛引用,你聲明變量時不指定引用類型就是強引用。我們知道Java是有一個垃圾回收機制GC的,一個變量被其他類引用,就會增加一個引用計數,只有當這個變量的引用計數降為0時,才會觸發GC的回收。因為當這個變量還被引用的時候,GC是不能回收掉這部分內存的,因為可能造成程序錯誤。而內存泄漏則發生在一個短週期的類裏面引用了一個長週期的變量,導致了短週期的這個類的引用計數為0本應該被回收,但是拖泥帶水地引用了一個還不能被回收的變量,比如一個耗時的文件讀寫操作。這個時候就導致了GC也沒有回收這個短週期的類,比如已經被finish的Activity。

如何檢測內存泄漏

檢測Android程序的內存泄漏其實很簡單,通常我們使用的是LeakCanary。只需要在app模塊的build.gradle中添加LeakCanary的依賴即可。 kts // 內存泄漏檢測 debugImplementation("com.squareup.leakcanary:leakcanary-android:2.10") 然後我們在打debug包的時候就會附帶安裝一個出詳細內存泄漏報告的一個名叫Leaks的app了。當app發生內存泄漏的時候,Leaks這個app就會自動幫你記錄內存泄漏了。

什麼是內存溢出

內存溢出是指程序在運行時需要的內存超出了系統所能提供的可用內存空間,導致程序崩潰或出現異常。在計算機程序中,內存通常被用來存儲程序的數據和指令,如果程序需要的內存超過了系統所能提供的內存空間,就會導致內存溢出的問題。

在Android手機系統中,也給每一個應用進程設置了一個能分配的最大內存上限。也正是因為這個上限,導致了一些動歪腦筋的應用開發者,給app開多個進程以搶佔更多的內存資源。但是,儘管這樣,你代碼寫的不好,難道你就不內存溢出了嗎?答案是否定的,就算把整個手機的內存都給你,也防止不了豬隊友寫的垃圾代碼導致的內存溢出。故意寫死循環導致程序卡死的這種情況就不是水平問題而上升到人品問題了。

在Android中內存溢出通常是由於加載大量Bitmap,而又沒有及時回收導致的。早期的開發者使用軟引用解決OOM問題,而現在這個框架橫生的時代,我們不用自己去解決圖片加載的OOM問題了,我們可以直接使用像Glide這樣的圖片加載框架,它會自動幫我們處理LruCache的問題,當內存不夠用的時候,按時間軸最早加載的那部分Bitmap會被釋放掉。

使用meminfo統計內存使用情況

adb shell "dumpsys meminfo" 執行這個命令看下你的應用的內存使用情況。我們再來看下與進程相關的VSS、RSS、PSS、USS這幾個概念。

  1. VSS(Virtual Set Size):進程保留供其使用的虛擬內存量。這包括私有和共享內存段。
  2. RSS(Resident Set Size):進程當前使用的物理內存量。這包括私有和共享內存段。
  3. PSS(Proportional Set Size):進程正在使用的內存量,在共享同一內存段的所有進程之間按比例共享。該指標通常用於識別多進程環境中進程的實際內存使用情況。
  4. USS(Unique Set Size):一個進程獨佔使用的內存量,不與任何其他進程共享。這包括私有和共享內存段。

翻譯成中文,VSS虛集合大小、RSS常駐集合大小、PSS比例集合大小和USS獨佔集合大小。VSS這個跟我們實際物理內存佔用關係並不大,比如一塊內存區域被多個變量引用,而實際這個VSS虛擬集合會重複統計,這個就是物理內存和程序虛擬內存的區別。RSS沒有將共享內存大小平分到使用共享內存的進程上,由於共享內存只會佔用一份內存,所以如果你把進程的RSS相加,就會超出很多。而PSS通常被用來衡量應用實際的內存使用情況。USS獨立內存,統計出來就不會包含多進程共享的那部分內存。

使用Android Studio的Profiler對內存進行分析

使用Android Studio自帶的內存分析工具分析內存使用情況,具體打開方式View > Tool Windows > Profiler

Profiler 選擇MEMORY選項可以看實時內存使用情況。然後切到CPU選項,選擇Java/Kotlin Method Trace點擊RECORD進行錄製,可以分析該段時間的方法調用情況。

總結

內存優化主要還是要靠開發中自行避免,在寫的時候就避免內存問題是最好的,防範於未然。避免寫出內存泄漏的代碼,比如謹慎使用static關鍵字,常量和工具方法可用。實在是遇到了可能造成內存泄漏的代碼,要轉換成弱引用WeakReference。避免寫出內存溢出的代碼,比如,使用Glide幫你處理圖片加載,儘量不要在大量調用的代碼塊(如循環或View的onDraw)裏面創建對象。仔細審查代碼也能避免內存問題的出現,在測試中也能發現內存問題,應用上線後在產品運營的分析中也還能發現,但是它們所帶來的結果是不一樣的。在整個環節的越早期處理掉內存問題越好,越到後面的環節,付出的代價如時間成本就會越大。