如何控制應用程序使用的內存?

1. 記得關閉啟動的服務

當服務中的任務完成後,要記得停止該服務。可以考慮使用 IntentService,因為IntentService 在完成任務後會自動停止。

2. UI 不可見時釋放資源

在 onStop 中關閉網絡連接、註銷廣播接收器、釋放傳感器等資源;

在 onTrimMemory() 回調方法中監聽TRIM_MEMORY_UI_HIDDEN 級別的信號,此時可在 Activity 中釋放 UI 使用的資源,大符減少應用佔用的內存,從而避免被系統清除出內存。

3. 內存緊張時釋放資源

運行中的程序,如果內存緊張,會在 onTrimMemory(int level) 回調方法中接收到以下級別的信號:

TRIM_MEMORY_RUNNING_MODERATE:系統可用內存較低,正在殺掉 LRU緩存中的進程。你的進程正在運行,沒有被殺掉的危險。

TRIM_MEMORY_RUNNING_LOW:系統可用內存更加緊張,程序雖然暫沒有被殺死的危險,但是應該盡量釋放一些資源,以提升系統的性能(這也會直接影響你程序的性能)。

TRIM_MEMORY_RUNNING_CRITICAL:系統內存極度緊張,而LRU緩存中的大部分進程已被殺死,如果仍然無法獲得足夠的資源的話,接下來會清理掉 LRU 中的所有進程,並且開始殺死一些系統通常會保留的進程,比如後臺運行的服務等。

當程序未在運行,保留在 LRU 緩存中時, onTrimMemory(int level) 中會返回以下級別的信號:

TRIM_MEMORY_BACKGROUND:系統可用內存低,而你的程序處在 LRU的頂端,因此暫時不會被殺死,但是此時應釋放一些程序再次打開時比較容易恢復的 UI 資源。

TRIM_MEMORY_MODERATE:系統可用內存低,程序處於 LRU的中部位置,如果內存狀態得不到緩解,程序會有被殺死的可能。

TRIM_MEMORY_COMPLETE:系統可用內存低,你的程序處於 LRU尾部,如果系統仍然無法回收足夠的內存資源,你的程序將首先被殺死。此時應釋放無助於恢復程序狀態的所有資源。

註:該 API 在版本 14 中加入。舊版本的onLowMemory() 方法,大致相當於 onTrimMemory(int level) 中接收到 TRIM_MEMORY_COMPLETE 級別的信號。

另:盡管系統主要按照 LRU 中順序來殺進程,不過系統也會考慮程序佔用的內存多少,那些佔用內存高的進程有更高的可能性會被首先殺死。

4. 確定你的程序應該佔用多少內存

可以通過 getMemoryClass()來獲取你的程序被分配的可用內存,以 M 為單位。

你可以通過在 <application> 標簽下將 largeHeap 屬性設為 true 來要求更多的內存,這時通過 getLargeMemoryClass() 方法來獲取可用內存。/<application>

大部分應用程序不需要使用此功能,因此使用該標簽前,確認你的程序是否真的需要更多內存。使用更多內存會對整個系統的性能產生影響,而且當程序進入 LRU時會更容易首先被系統清理掉。

5. 正確使用 Bipmap,避免浪費內存

如果你的 ImageViwe 的尺寸只有 100 * 100,那麼沒有必要將一張 2560 * 1600 的圖片整個加載入內存。

6. 使用 Android提供的優化過的數據結構

如 SparseArray, SparseBooleanArray, LongSparseArray 等,相比 Java 提供的 HashMap,這些結構更節省內存。

7. 始終對內存使用情況保持關註

枚舉類型 Enum 會比靜態常量佔用更多的內存;

Java 中每個類(包括匿名內部類)都佔用至少 500字節左右的代碼;

每個類的實例會在 RAM 中佔用大約 12 ~ 16 字節的內存;

每向 HashMap 中添加一個 Entry 時,新生成的 Entry 佔用大約 32 個字節。

8. 謹慎使用第三方類庫

這些外部類庫可能原先並非針對移動平臺,因此未進行過優化,在使用前應註意。另外盡量不要因為一兩個特性而使用一個體積很大的類庫。

9. 使用 ProGuard

使用 ProGuard 移除無用的代碼並重命名一些類、字段、方法等,使你的代碼更緊湊,節省內存空間。

10. 使用 zipalign

zipaligned 對最終打包的 apk進行字節對齊。

註:Google Play 不接受未對齊過的 apk。

11. 分析內存使用情況

如果已經獲得一個相對穩定的版本,應對程序整個生命週期的內存使用狀況進行分析。

12. 使用多個進程

如果程序需要執行大量的後臺工作,可考慮將程序分為兩個進程,一個進程負責 UI,另一個進程負責後臺任務。比如音樂播放器。

代碼示例:

<name>

android:process屬性的值以“:”開頭,名稱可任意選取。

在決定是否使用多進程前,應註意,一個不執行任何任務的空進程至少也要佔用 1.4 MB內存。

另外要註意進程的相互依賴性,比如如果將 ContentProvider 放在 UI 進程中,而後臺任務進程也需要調用 ContentProvider,就會導致 UI 進程一直保留在 RAM 中。


分享到:


相關文章: