Android中的記憶體洩漏

weixin_34075551發表於2017-06-23

1.什麼事記憶體洩漏

記憶體不在GC的掌控之中了
本來應該回收的物件,還存留在記憶體中,

(1)什麼是GC(垃圾回收機制)?

某物件不再有任何的任何的引用的時候才會進行回收,舉例(餐廳餐具回收),
延伸:GC回收機制的原理,深入的話去了解JVM虛擬機器
(GC ROOT TRACING回收演算法)
GC動作發生的時候,從一個GCROOT物件開始往下走,找到一個物件是被GCROOT物件所持有,那麼久不會回收,以此類推,只要持有就不會回收,找到沒有被引用的物件,就會標記為允許被回收的,例外情況,就是記憶體洩露了.
①可以被GCROOT物件引用的點是哪些?
在JAVA STACK中引用的物件
在方法區中靜態引用指向的物件
方法區中常量引用指向的物件
Native方法中JNI引用的物件
活著的Thread
②怎麼判斷一個物件是垃圾物件
垃圾物件就是沒有被引用嗎,no,沒有被引用是可以回收的,這是一個主觀判斷,假設我們new了一個物件,然後退出了程式,去記憶體中檢視,那這個物件也是垃圾物件,在GC眼裡這不是垃圾物件,但是在我們眼裡,這就是垃圾物件,

2.確定專案中存在記憶體洩漏

粗略判斷AndroidMonitor--System Infomations---Activity.View等數量是否為0

3.確定記憶體洩漏在哪兒

(1)AndroidStudioMemoryMonitor工具
(2)粗略估計不行的話,可以生成hprof檔案,用記憶體分析工具來分析,例如MAT,LeakCanary

4.常見的記憶體洩漏

記憶體洩漏產生的原因在Android中大致分為以下幾種:原部落格地址

(1).static變數引起的記憶體洩漏

因為static變數的生命週期是在類載入時開始 類解除安裝時結束,也就是說static變數是在程式程式死亡時才釋放,如果在static變數中 引用了Activity 那麼 這個Activity由於被引用,便會隨static變數的生命週期一樣,一直無法被釋放,造成記憶體洩漏。

解決辦法:
在Activity被靜態變數引用時,使用 getApplicationContext 因為Application生命週期從程式開始到結束,和static變數的一樣。

(2).執行緒造成的記憶體洩漏

類似於上述例子中的情況,執行緒執行時間很長,及時Activity跳出還會執行,因為執行緒或者Runnable是Acticvity內部類,因此握有Activity的例項(因為建立內部類必須依靠外部類),因此造成Activity無法釋放。
AsyncTask 有執行緒池,問題更嚴重

解決辦法:
1.合理安排執行緒執行的時間,控制執行緒在Activity結束前結束。
2.將內部類改為靜態內部類,並使用弱引用WeakReference來儲存Activity例項 因為弱引用 只要GC發現了 就會回收它 ,因此可儘快回收

(3).BitMap佔用過多記憶體

bitmap的解析需要佔用記憶體,但是記憶體只提供8M的空間給BitMap,如果圖片過多,並且沒有及時 recycle bitmap 那麼就會造成記憶體溢位。

解決辦法:
及時recycle 壓縮圖片之後載入圖片

(4).資源未被及時關閉造成的記憶體洩漏

比如一些Cursor 沒有及時close 會儲存有Activity的引用,導致記憶體洩漏

解決辦法:
在onDestory方法中及時 close即可

(5).Handler的使用造成的記憶體洩漏

由於在Handler的使用中,handler會傳送message物件到 MessageQueue中 然後 Looper會輪詢MessageQueue 然後取出Message執行,但是如果一個Message長時間沒被取出執行,那麼由於 Message中有 Handler的引用,而 Handler 一般來說也是內部類物件,Message引用 Handler ,Handler引用 Activity 這樣 使得 Activity無法回收。

解決辦法:
依舊使用 靜態內部類+弱引用的方式 可解決

(6).帶引數的單例

5.專案中的例子

(1)原來寫香信OA的時候,實現Banner滾動區域,使用了Thread的方法,while迴圈每隔五秒跳一下,------
(2)CIvetIM中,RxBus註冊的例子,
(3)==

相關文章