對於優化App內存方法你知道多少

本篇文章主要介紹 Android 開發中的部分知識點,通過閱讀本篇文章,您將收穫以下內容:
一、App內存優化概述
二、監視可用內存和內存使用情況
三、合理的釋放內存
四、分析App需要用多少內存
五、使用內存優化框架
六、移除內存密集型資源,以及lib庫

更多面試內容,面試專題,flutter視頻 全套,音視頻從0到高手開發。
關注GitHub:https://github.com/xiangjiana/Android-MS
免費獲取面試PDF合集

一、App內存優化概述

隨機存取存儲器(RAM)在任何軟件開發環境中都是非常有價值的資源,但對於物理內存經常受到限制的移動操作系統來說,它更有價值。儘管Android運行時(ART)Dalvik虛擬機都執行常規垃圾收集,但這並不意味着您可以忽略應用程序分配和釋放內存的時間和位置。您仍然需要避免引入內存泄漏,這些通常由靜態成員變量中的對象引用引起,並在生命週期回調定義的適當時間釋放任何引用對象。

本頁面介紹瞭如何主動減少應用程序中的內存使用量。有關Android操作系統如何管理內存的信息,請參閱Android內存管理概述

二、監視可用內存和內存使用情況

在修復解決APP中的內存使用問題之前,首先需要找到它們。 Android Studio中的內存分析器Memory Profiler可以幫助您通過以下方式查找和診斷內存問題:

1 . 查看App如何分配內存。

Memory Profiler顯示了一個實時圖,顯示您的應用程序使用了多少內存,分配了Java對象的數量以及何時發生垃圾回收。

2. 記錄GC快照

啓動垃圾收集事件並在運行應用程序時抓取Java堆的快照。

3.記錄您的應用程序的內存分配

然後檢查所有分配的對象,查看每個分配的堆棧跟蹤,然後跳轉到Android Studio編輯器中的相應代碼。

三、合理的釋放內存

Android可以通過多種方式從您的應用程序中回收內存,或者在必要時將應用程序徹底關閉以釋放內存以用於關鍵任務。爲了進一步幫助平衡系統內存,避免系統需要終止應用程序進程,可以在Activity類中實現ComponentCallbacks2接口提供的onTrimMemory()回調方法,從而允許您的應用程序在處於前臺或後臺時偵聽與內存相關的事件,然後釋放對象以響應應用程序生命週期,或者指示系統需要回收內存的系統事件。

例如,您可以實現onTrimMemory()回調以響應不同的內存相關事件,如下所示

  import android.content.ComponentCallbacks2;
  // Other import statements ...

  public class MainActivity extends AppCompatActivity
      implements ComponentCallbacks2 {

      // Other activity code ...

      /**
       * Release memory when the UI becomes hidden or when system resources become low.
       * @param level the memory-related event that was raised.
       */
      public void onTrimMemory(int level) {

          // Determine which lifecycle or system event was raised.
          switch (level) {

              case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:

                  /*
                     Release any UI objects that currently hold memory.

                     The user interface has moved to the background.
                  */

                  break;

              case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
              case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
              case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:

                  /*
                     Release any memory that your app doesn't need to run.

                     The device is running low on memory while the app is running.
                     The event raised indicates the severity of the memory-related event.
                     If the event is TRIM_MEMORY_RUNNING_CRITICAL, then the system will
                     begin killing background processes.
                    */

                    break;

              case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
              case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
              case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:

                  /*
                     Release as much memory as the process can.

                     The app is on the LRU list and the system is running low on memory.
                     The event raised indicates where the app sits within the LRU list.
                     If the event is TRIM_MEMORY_COMPLETE, the process will be one of
                     the first to be terminated.
                  */

                  break;

              default:
                  /*
                    Release any non-critical data structures.

                    The app received an unrecognized memory level value
                    from the system. Treat this as a generic low-memory message.
                  */
                  break;
          }
      }
  }

onTrimMemory() 回調方法是在Android 4.0時候添加的,之前版本請用onLowMemory()方法,跟TRIM_MEMORY_COMPLETE事件處理一樣。

四、分析App需要用多少內存

爲了允許多個正在運行的進程,Android爲每個應用程序分配的堆大小設置了硬限制。確切的堆大小限制根據設備有多少總體可用RAM不同而有所不同。如果您的應用程序已達到堆容量並嘗試分配更多內存,則系統將引發OutOfMemoryError

爲了避免OutOfMemoryError內存不足,可以查詢系統以確定當前設備上有多少可用的堆空間。你可以通過調用getMemoryInfo()來查詢這個數字。這將返回一個ActivityManager.MemoryInfo對象,該對象提供有關設備當前內存狀態的信息,包括可用內存,總內存以及內存閾值(即系統開始中斷進程的內存級別)。 ActivityManager.MemoryInfo對象還暴露了一個簡單的布爾值,lowMemory,可以判斷你設備是否在低內存下運行。

如下例子,舉例使用getMemoryInfo()

  public void doSomethingMemoryIntensive() {

      // Before doing something that requires a lot of memory,
      // check to see whether the device is in a low memory state.
      ActivityManager.MemoryInfo memoryInfo = getAvailableMemory();

      if (!memoryInfo.lowMemory) {
          // Do memory intensive work ...
      }
  }

  // Get a MemoryInfo object for the device's current memory status.
  private ActivityManager.MemoryInfo getAvailableMemory() {
      ActivityManager activityManager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
      ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
      activityManager.getMemoryInfo(memoryInfo);
      return memoryInfo;
  }

五、使用內存優化框架

一些Android功能,Java類和代碼構造傾向於使用比其他更多的內存。您可以通過在代碼中選擇更有效的替代方法來最大限度地減少應用程序使用的內存量

1. 謹慎使用Services

在不需要Services的情況下運行Services,是造成最嚴重的內存管理錯誤之一。
如果你的應用程序需要一個Services來在後臺執行工作,那麼除非它需要運行一個後臺任務,否則不要讓它保持運行。記得在完成任務時停止Services。否則,您可能會無意中造成內存泄漏。

當你啓動一個Services時, 系統需要始終保持運行該Services的進程。此行爲使得Services進程非常昂貴,因爲Services使用的RAM對其他進程仍然不可用。這樣可以減少系統在LRU緩存中保留的緩存進程的數量,從而降低應用程序切換的效率。內存不足時系統甚至可能導致系統崩潰,系統無法維護足夠的進程來承載當前運行的所有服務。

您通常應該避免使用持久性Persistent Services,因爲這些服務會常駐系統內存。相反,我們建議您使用諸如JobScheduler之類的替代實現。有關如何使用JobScheduler安排後臺進程的更多信息,請參閱後臺優化。

如果您必須使用服務,那麼限制服務使用壽命的最好方法就是使用IntentService,一旦完成了處理啓動它的意圖,IntentService就會自動完成。有關更多信息,請閱讀在後臺服務中運行。

2.使用更優化的數據容器

編程語言提供的某些類未針對在移動設備上使用進行優化。例如,通用的HashMap實現可能是相當低效的內存,因爲每個映射都需要單獨的入口對象。

Android框架包括幾個優化的數據容器,包括SparseArray,SparseBooleanArray和LongSparseArray。例如,SparseArray類更有效率,因爲它們避免了系統需要自動複製密鑰的情況,有時還需要創建另外一個或兩個對象。

如有必要,您可以隨時切換到原始數組以獲得精簡的數據結構。

3.使用nano protobufs進行序列化數據

協議緩衝區是一種語言中立,平臺無關,可擴展的機制,由Google設計,用於序列化結構化數據 - 類似於XML,但更小,更快,更簡單。如果你決定爲你的數據使用protobufs,你應該總是在你的客戶端代碼中使用nano protobufs。經常protobufs生成非常詳細的代碼,這可能會導致您的應用程序中的許多種問題,如增加的RAM使用,APK大小增加,和較慢的執行。

有關更多信息,請參閱protobuf自述文件中的“Nano版本”部分。

4.避免內存泄漏

如前所述,垃圾收集事件通常不會影響您的應用程序的性能。但是,很多短時間內發生的垃圾收集事件可能會很快消耗掉你的幀時間。系統花費在垃圾收集上的時間越多,執行其他內容(如渲染或流式傳輸音頻)的時間就越少。

內存流失通常會導致大量的垃圾收集事件發生。在實踐中,內存流失描述了在給定的時間內發生的分配的臨時對象的數量。

例如,您可以在for循環中分配多個臨時對象。或者您可以在視圖的onDraw()函數內創建新的PaintBitmap對象。在這兩種情況下,應用程序都會以大批量快速創建大量對象。這些可能會迅速消耗年輕一代中的所有可用內存,從而迫使垃圾收集事件發生。

當然,你需要在你的代碼中找到內存流失高的地方,然後才能修復它們。爲此,您應該在Android Studio中使用Memory Profiler

六、移除內存密集型資源,以及lib庫

你的代碼中的一些資源和庫可以在你不知道的情況下吞噬內存。您的APK的整體大小(包括第三方庫或嵌入式資源)可能會影響您的應用消耗的內存量。您可以通過從代碼中刪除冗餘,不必要或臃腫的組件,資源或庫來改善應用程序的內存消耗。

1.減小APK的大小

您可以通過減少應用程序的整體大小來顯着減少應用程序的內存使用量。比如:bitmap大小,res資源,動畫幀數以及第三方庫都可以影響APK的大小。 Android StudioAndroid SDK提供了多種工具來幫助您減少資源和外部依賴的大小。

有關如何減少您的整體APK大小的更多信息,請參閱縮小APK大小。

2.使用Dagger 2進行依賴注入

依賴注入框架可以簡化您編寫的代碼,並提供適用於測試和其他配置更改的自適應環境。

如果您打算在應用程序中使用依賴項注入框架,請考慮使用Dagger 2. Dagger 2不使用反射來掃描您的應用程序的代碼。Dagger的靜態編譯實現,意味着它可以在Android應用程序中使用,而無需增加運行成本或內存使用。

其他使用反射的依賴注入框架傾向於通過掃描代碼來註釋來初始化進程。這個過程可能需要更多的CPU週期和內存,並且在應用程序啓動時會引起明顯的滯後

3.謹慎使用外部庫

外部庫代碼通常不是針對移動環境編寫的,而且在用於移動客戶端時可能效率低下。當您決定使用外部庫時,您可能需要爲移動設備優化該庫。預先計劃好這個工作,然後根據代碼大小和內存佔用情況來分析這個庫,然後才決定使用它。

即使一些移動優化的庫可能由於不同的實現而導致問題。例如,一個庫可能使用nano protobufs,而另一個庫使用微型protobufs,導致您的應用程序中有兩個不同的protobuf實現。這可能發生在不同的日誌記錄,分析,圖像加載框架,緩存以及許多您不希望的事情上。

儘管ProGuard可以幫助您使用正確的標誌刪除API和資源,但它不能刪除庫的大型內部依賴關係。您需要在這些庫中的功能可能需要較低級別的依賴關係。如果庫使用反射,這是常見的,並且意味着您需要花費大量時間手動調整ProGuard才能使用反射,那麼當您從庫中使用Activity子類時,這往往會產生大量的依賴關係工作等等。。

更多面試內容,面試專題,flutter視頻 全套,音視頻從0到高手開發。
關注GitHub:https://github.com/xiangjiana/Android-MS
免費獲取面試PDF合集

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章