必定要注意 Android 內存泄漏問題

內存泄漏是引發Android應用崩潰常見的緣由,每一個Android開發人員都應該明白怎麼避免發送。 經常使用的分析內存的工具備 Android ProfilerLeakCanaryjava

Android ProfilerLeakCanary

Android Profiler 是Android Studio提供的一個工具,用於實時觀察應用的狀況,包括:內存、CPU、網絡等。android

LeakCanary 是一個第三方庫,用於分析內存泄漏。官方地址:square.github.io/leakcanary/git

什麼是內存泄漏

是什麼致使了內存泄漏呢?當你的代碼爲一個對象分配了內存,可是卻沒有釋放,就會形成內存泄漏,固然沒有釋放的緣由有不少種。github

不論是什麼緣由,沒有釋放,是由於這個對象依然被別的對象引用,可是這些被引用的對象應該是要被銷燬的。網絡

Android 爲每一個應用限制的最大內存使用量,當使用的內存超過最大值之後就會引起OOM,是程序奔潰,因此咱們要嚴格限制內存的使用。框架

爲何咱們須要關注內存

系統回收內存的時候,你的程序會暫停,但一般這個過程是很是短暫的,通常用戶感知不到。ide

可是有的時候你注意到你的程序變的緩慢和掉針,這是由於回收內存已經趕不上分配內存的速度了。工具

當內存泄漏發生的時候,內存會不斷的增長,致使不斷的觸發gc,進而致使程序卡頓,甚至系統會強制殺死你的程序已便回收內存。字體

基於這些緣由,咱們必須的關注內存。優化

簡單介紹下java內存模型

Java內存模型分爲Jvm內存模型和Jmm內存模型。Jvm是java虛擬機內存模型,而Jmm內存模型是隻爲java程序服務。咱們一般討論的Java內存模型,更多的是在討論Jvm。

Jvm內存模型中按照線程是否獨佔,能夠分爲兩部分。線程獨佔內存區有棧,本地方法棧和程序計數器,全部線程共享的有堆和方法區。

  • 也被稱爲Java虛擬機棧,它的生命週期與線程相同。每一個方法在執行的同時都會建立一個棧幀(Stack Frame)用於存儲局部變量、操做數棧、動態連接、方法出口等信息。每一個方法從開始調用到執行完成對應入棧和出棧的過程。這個區域有兩種異常狀況:1,若是請求的深度大於虛擬機容許的深度,拋出StackOverflowError異常。2,若是擴展時沒法申請到足夠的內存,會拋出OutOfMemoryError異常。
  • 本地方法棧 和虛擬機棧相似,不過不是執行Java方法,而是執行本地方法。同Java虛擬機棧同樣會拋出StackOverflowError和OutOfMemoryError異常。
  • 程序計數器 是一塊較小的內存空間,用來保存當前程序執行的字節碼位置。此內存是Java虛擬機中惟一快沒有指定OutOfMemoryError的區域。只爲執行Java方法服務。
  • 是Java中最大的一塊內存,主要用於保存對象實例,幾乎全部的線程對象實例都在這裏分配內存。這也是垃圾回收器最主要的管理區域。內存不足時將會拋出OutOfMemoryError異常。
  • 方法區 用於存儲類信息、常量、靜態變量,即時編譯器編譯後的代碼等數據。也叫非堆區。

Android 的內存有哪些

咱們可使用Android Sudio的 Memory Profiler 中查看App的內存狀況。

內存計數中的類別以下:

  • Java:從 Java 或 Kotlin 代碼分配的對象的內存。

  • Native:從 C 或 C++ 代碼分配的對象的內存。 即便您的應用中不使用 C++,您也可能會看到此處使用的一些原生內存,由於 Android 框架使用原生內存表明您處理各類任務,如處理圖像資源和其餘圖形時,即便您編寫的代碼採用 Java 或 Kotlin 語言。

  • Graphics:圖形緩衝區隊列向屏幕顯示像素(包括 GL 表面、GL 紋理等等)所使用的內存。(請注意,這是與 CPU 共享的內存,不是 GPU 專用內存。)

  • Stack:您的應用中的原生堆棧和 Java 堆棧使用的內存。這一般與您的應用運行多少線程有關。

  • Code:您的應用用於處理代碼和資源(如 dex 字節碼、通過優化或編譯的 dex 代碼、.so 庫和字體)的內存。

  • Others:您的應用使用的系統不肯定如何分類的內存。

  • Allocated:您的應用分配的 Java/Kotlin 對象數。此數字沒有計入 C 或 C++ 中分配的對象。

    若是鏈接到搭載 Android 7.1 及更低版本的設備,只有在 Memory Profiler 鏈接到您運行的應用時,纔開始此分配計數。所以,您開始分析以前分配的任何對象都不會被計入。不過,Android 8.0 及更高版本附帶一個設備內置分析工具,該工具可跟蹤全部分配,所以,在 Android 8.0 及更高版本上,此數字始終表示您的應用中待處理的 Java 對象總數。

Android中常見的內存泄漏

Android 中常見的內存泄漏來自Activity,Service,View等組件的不當使用。好比當一個Activity在被銷燬後,還被別的對象持有的狀況下,gc就無法回收這個activity,致使內存泄漏。 咱們來看一個內存泄漏的例子:

class MemoryLeakDemoActivity : AppCompatActivity() {

    companion object {
        private var activities: MutableList<Activity>? = mutableListOf()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_memory_leak_demo)

        // 這會形成內存泄漏
        activities?.add(this)
    }
}
複製代碼

這段代碼中,在onCreate方法咱們把當前activity對象加入到單例列表中,這樣當這個activity被銷燬後,卻不能被gc回收,由於其對象還在被引用,這就形成了內存的泄漏。

總結

Android 對內存的要求的比較嚴格,每一個應用程序可以使用的內存都是有限的,不合理的使用內存會形成程序卡頓,甚至崩潰,因此每個開發者都應該要關注內存的使用狀況。

參考

developer.android.com/studio/prof…

相關文章
相關標籤/搜索