安卓內存泄漏8種可能


     java垃圾回收器,開發者無需特意管理內存分配,降低了應用由於局部故障導致崩潰,同時防止未釋放的內存把堆棧擠爆的可能,所以寫出的代碼更為安全。

         但是,在java中仍存在很多容易導致內存泄漏的邏輯可能。如果不小心,則很容易浪費掉未釋放的內存,最終導致內存用光的錯誤拋出OOM

         內存泄漏

  1. 一般內存泄漏(traditional memory leak):由忘記釋放分配的內存導致的(Cursor忘記關閉等)
  2. 邏輯內存泄漏(logical memory leak):當應用不再需要這個對象,但仍未釋放該對象的所有引用

 

如果持有對象的強引用,垃圾回收器是無法在內存中回收這個對象

       Android 中,最容易引發的內存泄漏為 Context,如Activity的Context,就包含了大量的內存引用,如View Hierarchies和其他資源。一旦泄漏Context,就意味着泄漏它指向的所有對象。android機器內存有限,太多的內存泄漏容易導致OOM

       Activity.onDestroy()被視為Activity生命的結束,程序上看來,它應該被銷毀,或者Android系統需要回收這些內存(當內存不夠時,android會回收看不見的activity)

       如果Activity.onDestroy()執行完,堆棧中仍存在持有該activity的引用,垃圾回收器就無法把他標記成已回收的內存(結果就是Activity存活在它的生命周期之外)

       導致潛在的內存泄漏的陷阱不外乎兩種:

  1. 全局進程(process-global)的static變量。這個無視應用狀態,持有activity的強引用的東西
  2. 活在Activity生命周期之外的線程。沒有清空對Activity的強引用。

----------------------------------------------------------------------------------------------------------------

Static Activity

       在類中定義了靜態Activity變量,把當前運行的activity實例賦值於這個靜態變量。

        如果這個靜態變量在activity生命結束后沒有清空,就會導致內存泄漏。因為static貫穿了這個應用的生命周期,所以被泄露的Activity就會一直存在於應用的進程中,不會被垃圾回收器回收。 

 

       避免這種代碼        static Activity activity;

----------------------------------------------------------------------------------------------------------------

Static Views      單例中保存activity

        在單例中,如果Activity經常被用到,那么內存中保存一個實例是很實用的。但由於單例的生命周期是應用程序的生命周期,這樣做會延長Activity的生命周期(強制延長Activity的生命周期是相當危險且不必要的,無論如何都不能在單例中保存類似的Activity對象)

         特殊情況:如果一個View初始化耗費大量資源,而且在一個activity生命周期內保持不變,那可以把它變成static,加載到視圖樹上(View Hierachy),像這樣,當activity被銷毀時,應當釋放資源。(在銷毀視圖時應該把這個static view的view置為null)

 

        在調用Singleton的getInstance()方法時傳入了Activity,那么當instance 沒有釋放時,這個Activity會一直存在。因此造成內存泄漏。

         可以在傳入context時傳入context.getApplicationContext()即可

          static view也不建議,或者應該在銷毀時置null

        Inner Classes:提高可讀性,但是導致內存泄漏的原因,就是內部持有外部類實例的強引用,如內部類中持有Activity對象

        解決辦法,1.將內部類變為靜態內部類,把匿名內部類變為靜態匿名內部類

                          2.如果有強引用Activity中的屬性,則將該屬性的引用方式改為弱引用

                          3.在業務運行的情況下,當Activity執行onDestroy時,結束這些耗時任務

----------------------------------------------------------------------------------------------------------------

Inner Classes

        假設Activity中有個內部類,這樣做可以提高可讀性和封裝性。假如我們創建一個內部類,而且持有一個靜態變量的引用,那么很有可能內存泄漏(銷毀的時候置空即可)

        內部類的優勢之一就是可以訪問外部類,不好的是,導致內存泄漏的原因,就是因為內部類持有外部類實例的引用。

----------------------------------------------------------------------------------------------------------------

Anonymous Classes

        匿名類也維護了外部類的引用。所以內存泄漏很容易發生,當你在Activity中定義了匿名的AsyncTask。當陰補任務在后台執行耗時任務期間,Activity不幸被銷毀(用戶退出,系統回收),這個被AsyncTask持有的Activity實例就不會被垃圾回收器回收,直到異步任務結束。

----------------------------------------------------------------------------------------------------------------

Handler

         同樣,定義匿名的Runnable,用匿名Handler執行。Runnable內部類會持有外部類的隱式引用,被傳遞到Handler的消息隊列MessageQueue中,在Message消息沒有被處理之前,Activity實例不會被銷毀,於是導致了內存泄漏。

----------------------------------------------------------------------------------------------------------------

Threads

        只要是匿名類的實例,不管是不是在工作線程,都會持有Activity的引用,導致內存泄漏

----------------------------------------------------------------------------------------------------------------

TimerTask

        只要是匿名類的實例,不管是不是在工作線程,都會持有Activity的引用,導致內存泄漏

----------------------------------------------------------------------------------------------------------------

Sensor Manager

         通過Context.getSystemService(int name) 可獲取系統服務。這些服務工作在各自的進程中,幫助應用處理后台任務,處理硬件交互。如果需要使用這些服務,可注冊監聽器,這會導致服務持有了Context的引用,如果在Activity銷毀的時候沒有注銷這些監聽,會導致內存泄漏

 

 

http://tryenough.com/android-momeryleak內存泄漏及解決方式

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM