1. 程式人生 > >Android常見內存泄露,學會這六招優化APP性能

Android常見內存泄露,學會這六招優化APP性能

roi mage 們的 baidu 程序 面試 監控 服務 沒有

  1. 很多開發者都知道,在面試的時候會經常被問到內存泄露和內存溢出的問題。

    1.內存溢出(Out Of Memory,簡稱 OOM),通俗理解就是內存不夠,即內存占用超出內存的空間大小。

    2.內存泄漏(Memory Leak),簡單理解就是內存使用完畢之後本該垃圾回收卻未被回收。

    技術分享
  2. 2

    在正式了解內存泄露之前,首先來簡單回顧一下 Java 內存分配策略。

    Java 程序運行時的內存分配策略有三種,分別是靜態分配、棧式分配、堆式分配,對應的主要內存空間分別是靜態存儲區(也稱方法區)、棧區、堆區。

    1.靜態存儲區(方法區)

    主要存放靜態數據、全局 static 數據和常量。這塊內存在程序編譯時就已經分配好,並且在程序整個運行期間都存在。

    2.棧區

    當方法被執行時,方法體內的局部變量都在棧上創建,並在方法執行結束時這些局部變量所持有的內存將會自動被釋放。因為棧內存分配運算內置於處理器的指令集中,效率很高,但是分配的內存容量有限。

    3.堆區

    又稱動態內存分配,通常就是指在程序運行時直接 new 出來的內存。這部分內存在不使用時將會由 Java 垃圾回收器來負責回收。

    技術分享
  3. 3

    在 Java 中,內存的分配是由程序完成的,而內存的釋放是由 GC 完成的,這種方式大大簡化了程序員的工作,但同時卻加重了 JVM 的工作,這也是 Java 程序運行速度較慢的原因之一。GC 為了能夠正確釋放對象,必須監控每一個對象的運行狀態,包括對象的申請、引用、被引用、賦值等,監視對象的狀態是為了更加準確地、及時地釋放對象,而釋放對象的根本原則就是該對象不再被引用。

    END

內存泄露

  1. 1

    Java 有了垃圾回收功能,程序員無需手動管理內存分配,減少了段錯誤導致的閃退,也減少了內存泄漏導致的堆空間膨脹,讓編寫的代碼更加安全。但是 Java 中依然有可能發生內存泄露,而 Android 主要使用 Java 作為開發語言,在開發過程中很可能一個很小的錯誤都會引起內存的泄露。有內存泄露存在時,APP 就會浪費大量的內存,就會由於內存不夠而頻繁進行垃圾回收,大家知道垃圾回收是非常耗時的操作,這樣就會導致 APP 的嚴重卡頓。在最壞的時候,甚至由於內存耗盡導致OutOfMemery,最終程序異常退出。

  2. 2

    內存泄露是一個令很多開發者頭疼的問題,那麽我們今天就來學習一下 Activity 有關的內存泄露問題。

    在 Android 中,泄露 Context 對象的問題尤其嚴重,特別像 Activity 這樣的 Context 對象會引用大量很占用內存的對象,如果 Context 對象發生了內存泄漏,那它所引用的所有對象都被泄漏了。Activity 是非常重量級的對象,所以我們應該極力避免妨礙系統對其進行回收,然而實際情況是有多種方式會無意間就泄露了Activity 對象。

    技術分享 END

Activity 六招優化性能秘籍

  1. 1

    1. 靜態變量造成的內存泄漏

    最簡單的泄漏 Activity 就是在 Activity 類中定義一個 static 變量,並將其指向一個運行中的 Activity 實例。如果在 Activity 的生命周期結束之前,沒有清除這個引用,那它就會泄漏。由於 Activity 的類對象是靜態的,一旦加載,就會在 APP 運行時一直常駐內存,如果類對象不卸載,其靜態成員就不會被垃圾回收。

  2. 2

    2. 單例造成的內存泄漏

    另一種類似的情況是對經常啟動的 Activity 實現一個單例模式,讓其常駐內存可以使它能夠快速恢復狀態。

    如我們有一個創建起來非常耗時的 View,在同一個 Activity 不同的生命周期中都保持不變呢,就為它實現一個單例模式。一旦 View 被加載到界面中,它就會持有 Context 的強引用,也就是我們的 Activity 對象。

    由於我們是通過一個靜態成員引用了這個 View,所以我們也就引用了 Activity,因此 Activity 就發生了泄漏。所以一定不要把加載的 View 賦值給靜態變量,如果你真的需要,那一定要確保在 Activity 銷毀之前將其從 View 層級中移除。

  3. 3

    3. 內部類造成的內存泄漏

    我們經常在 Activity 內部定義一個內部類,這樣做可以增加封裝性和可讀性。但是如果當我們創建了一個內部類的對象,並通過靜態變量持有了 Activity 的引用,那也會可能發生 Activity 泄漏。

  4. 4

    4. 線程造成的內存泄漏

    在 Activity 內定義了一個匿名的 AsyncTask 對象,就有可能發生內存泄漏。如果 Activity 被銷毀之後 AsyncTask 仍然在執行,那就會阻止垃圾回收器回收Activity 對象,進而導致內存泄漏,直到執行結束才能回收 Activity。

    同樣的,使用 Thread 和 TimerTask 也可能導致 Activity 泄漏。只要它們是通過匿名類創建的,盡管它們在單獨的線程被執行,它們也會持有對 Activity 的強引用,進而導致內存泄漏。

  5. 5

    5.Handler 造成的內存泄漏

    定義一個匿名的 Runnable 對象並將其提交到 Handler 上也可能導致 Activity 泄漏。Runnable 對象間接地引用了定義它的 Activity 對象,而它會被提交到Handler 的 MessageQueue 中,如果它在 Activity 銷毀時還沒有被處理,就會導致 Activity 泄漏。

  6. 6

    6. 資源未關閉造成的內存泄漏

    如系統服務可以通過 context.getSystemService 獲取,它們負責執行某些後臺任務,或者為硬件訪問提供接口。如果 Context 對象想要在服務內部的事件發生時被通知,那就需要把自己註冊到服務的監聽器中。然而,這會讓服務持有 Activity 的引用,如果開發者忘記在 Activity 銷毀時取消註冊,也會導致 Activity泄漏。

    END

總結

  1. 1

    這裏只是簡單的分析了常見的有關 Activity 導致的內存泄露,其實導致內存泄露的地方還有很多,但是基本原理都一樣。由於篇幅原因,這裏不做過多介紹,以後再逐漸進行分析和學習。

    雖然現在手機內存越來越大,內存泄露不會像以前由於內存過小造成 OOM。但是過量的內存泄露依然會造成內存溢出,影響用戶體驗,所以解決好內存泄露的問題非常重要。

Android常見內存泄露,學會這六招優化APP性能