1. 程式人生 > >Android Weak Handler:可以避免記憶體洩漏的Handler庫

Android Weak Handler:可以避免記憶體洩漏的Handler庫

這是一個針對技術開發者的一個應用,你可以在掘金上獲取最新最優質的技術乾貨,不僅僅是Android知識、前端、後端以至於產品和設計都有涉獵,想成為全棧工程師的朋友不要錯過!

android使用java作為其開發環境。java的跨平臺和垃圾回收機制已經幫助我們解決了底層的一些問題。但是儘管有了垃圾回收機制,在開發android的時候仍然時不時的遇到out of memory的問題,這個時候我們不禁要問,垃圾回收機器去哪兒了?

我們主要講的是handler引起的洩漏,並給出三種解決辦法,其中最後一種方法就是我們想介紹的WeakHandler 庫。

可能導致洩漏問題的handler一般會被提示 Lint警告:

This Handler class should be static or leaks might occur 意思:class使用靜態宣告否者可能出現記憶體洩露。

這是一個基本的activity。在handler的post方法中我們加入了一個匿名的runnable,同時我將其執行延遲了整整80秒。我們執行這個程式,並且旋轉幾次手機,然後分析記憶體。

現在記憶體中有7個activity了,這太不靠譜了,所以我們來研究下為什麼GC沒有清理它。(上圖中我查詢記憶體中activity列表時用的是oql(物件查詢語言),簡單強大的工具,ps 怎麼用的,誰能告訴我?)

從上圖中我們可以看到其中一個對mainactivity的引用是來自this$0

this$0是什麼呢?以下是關於this$0的解釋:

-------什麼是this$0---------

非static的inner class裡面都會有一個this$0的欄位儲存它的父物件。在Java中,非靜態(匿名)內部類會預設隱性引用外部類物件。而靜態內部類不會引用外部類物件。一個編譯後的inner class 很可能是這樣的:

1 2 3 4 5 6 7 8 9 class parent$inner { synthetic parent this$0; parent$inner(parent this$0) { this.this
$0 = this$0; this$0.foo(); } }

-------什麼是this$0結束---------

在我們的程式碼中,匿名的runnable是一個非靜態的內部類,因此他會使用this$0來儲存MainActivity,然後runnable會繼續被它的callback引用,而callback又接著被接下來一連串的message引用,這樣主執行緒的引用就太他媽多了。 當Activity finish後,延時訊息會繼續存在主執行緒訊息佇列中80秒,然後處理訊息,因此handler在繼續存在於記憶體中,而handler引用了Activity,在我們旋轉手機的時候,Activity 不停的重建和finish,導致多個activity的引用出現。

一旦將Runnable或者是Message 傳送進handler,將儲存一連串的引用了主執行緒(這裡是MainActivity吧)的Message命令,直到message執行完。如果傳送Runnable設定了延遲時間,那麼至少在這段延遲時間內記憶體洩漏是肯定的,如果是直接傳送,在Message比較大的情況下,也是有可能發生暫時的洩漏的。

解決辦法一:使用Static

再次執行,同時旋轉手機,分析記憶體如下:

Analyse static runnable HPROF

尼瑪,還是一樣的。我們看看是誰還拉著activity不放:

Analyse static runnable HPROF

在最底下我們發現activity繼續被DoneRunnable裡面mTextView中的mContext引用著。看來在這種情況下,看來僅僅使用static並沒有解決問題啊。還需要做點工作才行。

靜態的Runnable加WeakReference

既然是因為mTextView引起的,那我們把mTextView換成弱引用好了:

Static runnable with weak reference

需要注意的,既然mTextView是弱引用,所以隨時都可能為null,因此需要在使用前判斷是否為空。好了繼續看看記憶體的情況:

Analyse static runnable with weak reference HPROF

all right,我想我們已經完美的解決問題了。總結一下我們做了哪些工作:

使用靜態的內部類

對所有handler/Runnable中的變數都用弱引用。

但是這種方式程式碼是不是很多,而且還必須得小心翼翼。

在onDestroy中清理掉所有Messages

Handler有個很方便的方法:removeCallbacksAndMessages,當引數為null的時候,可以清除掉所有跟次handler相關的Runnable和Message,我們在onDestroy中呼叫次方法也就不會發生記憶體洩漏了。

Remove callbacks code

執行,旋轉手機

Analise remove callbacks HPROF

但是如果你對程式碼有更高的要求,覺得這樣還不方便可以使用作者提供的WeakHandler

WeakHandler

WeakHandler使用起來和handler一模一樣,但是他是安全的,WeakHandler使用如下:

WeakHandler code

你只需要把以前的Handler替換成WeakHandler就行了。

WeakHandler的實現原理

WeakHandler的思想是將Handler和Runnable做一次封裝,我們使用的是封裝後的WeakHandler,但其實真正起到handler作用的是封裝的內部,而封裝的內部對handler和runnable都是用的弱引用。

WeakHandler diagram

第一幅圖是普通handler的引用關係圖

第二幅圖是使用WeakHandler的引用關係圖

其實原文有對WeakHandler更多的解釋,但是表述起來也挺複雜的。

相關推薦

Android Weak Handler可以避免記憶體洩漏Handler

這是一個針對技術開發者的一個應用,你可以在掘金上獲取最新最優質的技術乾貨,不僅僅是Android知識、前端、後端以至於產品和設計都有涉獵,想成為全棧工程師的朋友不要錯過! android使用java作為其開發環境。java的跨平臺和垃圾回收機制已經幫助我們解決了底層的一些問題。但是儘管有了垃圾回收機

Android Handler 避免記憶體洩漏之清空佇列

Android開發經常會用到handler,但是我們發現每次使用Handler都會出現:This Handler class should be static or leaks might occur(null)這樣的提示。Android lint就是為了提示我們,這樣使

Android開發-Handler引起的記憶體洩漏-實驗、分析、總結。

介紹 最近在惡補Handler的知識,其中就涉及到了Handler引起的記憶體洩露問題,網路上有很多的分析文章。我就按照這些文章的思路,寫程式碼驗證,主要是驗證和記錄。  使用的記憶體檢測工具是:LeakCanary 中文使用說明 英文原文: http://www

Kotlin中handler避免記憶體洩漏

前言: Handler在Android開發中經常使用,一不小心就會陷入記憶體洩漏的問題,最近在開發一款Kotlin軟體,針對Handler記憶體洩漏的問題做出瞭解決方案 問題分析: 在fini

handler機制的記憶體洩漏問題(handler + WeakReference優化Activity)

handler機制導致記憶體洩漏的原因:         Activity在被結束之後,MessageQueue並不會隨之被結束,如果這個訊息佇列中存在msg,則導致持有handler的引用,但是又由於Activity被結束了,msg無法被處理,從而導致永

優雅地使用Handler避免記憶體溢位、空指標

在Activity中直接建立Handler的內部類,比如這樣: public class HandlerActivity extends AppCompatActivity { private Handler mHandler = new Handler() {

關於Handler和AsyncTask記憶體洩漏的解決辦法

一、Handler的記憶體洩漏 This Handler class should be static or leaks might occur (anonymous android.os.Handler) less... (Ctrl+F1) Since t

[轉]Android 如何有效的解決記憶體洩漏的問題 Android 如何有效的解決記憶體洩漏的問題

Android 如何有效的解決記憶體洩漏的問題   前言:最近在研究Handler的知識,其中涉及到一個問題,如何避免Handler帶來的記憶體溢位問題。在網上找了很多資料,有很多都是互相抄的,沒有實際的作用。 本文的記憶體洩漏檢測工具是:LeakCanary &nbs

Android 如何有效的解決記憶體洩漏的問題

前言:最近在研究Handler的知識,其中涉及到一個問題,如何避免Handler帶來的記憶體溢位問題。在網上找了很多資料,有很多都是互相抄的,沒有實際的作用。 本文的記憶體洩漏檢測工具是:LeakCanary  github地址:https://github.com/square/le

Android---解決WebView導致的記憶體洩漏

如何解決WebView導致的記憶體洩漏 懶得廢話: 1.避免在xml佈局檔案中直接巢狀webview控制元件,而是採用addview的方式new一個webview並載入到佈局中,如: w

在 POSIX 執行緒程式設計中避免記憶體洩漏

POSIX 執行緒簡介 使用執行緒的主要原因是要提高程式效能。執行緒的建立和管理只需要較小的作業系統開銷和較少的系統資源。一個程序內的所有執行緒共享相同的地址空間,使得執行緒間的通訊更高效,且比程序間通訊更易於實現。例如,如果一個執行緒在等待一個輸入/輸出系統呼叫完成,其他執行緒可以處理 CPU 密集型任務

在JNI程式設計中避免記憶體洩漏(二)

JAVA 程式設計中的記憶體洩漏,從洩漏的記憶體位置角度可以分為兩種:JVM 中 Java Heap 的記憶體洩漏;JVM 記憶體中native memory 的記憶體洩漏。 Java 物件儲存在 JVM 程序空間中的 Java Heap 中,Java Heap 可以在 JVM 執行過程中動態變化。如果

記憶體優化(二)如何避免記憶體洩漏

文章目錄 一、不同生命週期導致的記憶體洩漏 解決辦法 二、非靜態內部類持有物件導致的記憶體洩漏 1. 非靜態內部類呼叫外部類的方法的 2. 內部類是如

在 JNI 程式設計中避免記憶體洩漏與崩潰

JNI 程式設計簡介 JNI,Java Native Interface,是 native code 的程式設計介面。JNI 使 Java 程式碼程式可以與 native code 互動——在 Java 程式中呼叫 native code;在 native code 中

c++避免記憶體洩漏

在c/c++語言對於程式記憶體的管理不像java語言一樣有自己的垃圾回收機制,而c/c++卻要程式設計師手動的釋放用關鍵字new或者 malloc系統函式申請的記憶體空間,然而由於程式設計師的疏忽可能

詳解java記憶體洩露和如何避免記憶體洩漏

源地址:http://www.xttblog.com/?p=518 一直以來java都佔據著語言排行榜的頭把交椅。這是與java的設計密不可分的,其中最令大家喜歡的不是面向物件,而是垃圾回收機制。你只需要簡單的建立物件而不需要負責釋放空間,因為Java的垃圾回收器會負責記憶

Android開發————分析Native層記憶體洩漏

Android開發——使用DDMS分析Native層記憶體洩漏 針對Java層的記憶體洩漏,Android提供了方便的記憶體洩漏檢測工具,例如MAT、LeakCanary。但對於native層開發,要追查C/C++程式碼的記憶體洩漏,valgrind等常用工具

Handle & Inner Classes 如何避免記憶體洩漏

檢視下面一段程式碼 public class SampleActivity extends Activity { private final Handler mLeakyHandler = new Handler() { @Override

Android WebView Memory Leak WebView記憶體洩漏

在這次開發過程中,需要用到webview展示一些介面,但是載入的頁面如果有很多圖片就會發現記憶體佔用暴漲,並且在退出該介面後,即使在包含該webview的Activity的destroy()方法中,使用webview.destroy();webview=null;對記憶體佔回收用還是沒有任何效果。有人說,一旦

Android效能測試CPU記憶體監控工具APT

1.APT工具簡介: APT是一個eclipse外掛,可以實時監控Android手機上多個應用的CPU、記憶體資料曲線,並儲存資料;另外還支援自動獲取記憶體快照、PMAP檔案分析等,方便開發人員自測或者測試人員完成效能測試,快速發現產品問題。專案地址:https://c