国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android Handler內存泄漏詳解及其解決方案

2019-10-21 21:41:43
字體:
來源:轉載
供稿:網友

在android開發過程中,我們可能會遇到過令人奔潰的OOM異常,面對這樣的異常我們是既熟悉又深惡痛絕的,因為造成OOM的原因有很多種情況,如加載圖片過大,某已不再使用的類未被GC及時回收等等......本篇我們就來分析其中一種造成OOM的場景,它就是罪惡的內存泄漏。對于這樣的稱呼,我們并不陌生,甚至屢次與之"并肩作戰",只不過它就是一個豬隊友,只會不斷送塔.......

本篇分為3部分:

1.Handler內存泄漏例子說明以及原理闡明

2.問題驗證(如果感覺繁瑣請直接跳過)

3.Handler內存泄漏解決方法

1.Handler內存泄漏例子說明以及原理闡明

Handler,我們已經相當熟悉了,而且經常用得不亦樂乎,但就是因為太熟悉了,才會偶爾被它反捅一刀,血流不止......還記得我們曾經滿懷信心地使用著如下的優美而又簡潔的代碼不?

Android,Handler,內存泄漏

不怕你嚇著,實話告訴你,這個代碼已經造成內存泄漏了!!!不相信?我們使用Android lint工具檢測一下該類的代碼:

Android,Handler,內存泄漏

面對現實吧,那為什么會這樣呢?在java中非靜態內部類和匿名內部類都會隱式持有當前類的外部引用,由于Handler是非靜態內部類所以其持有當前Activity的隱式引用,如果Handler沒有被釋放,其所持有的外部引用也就是Activity也不可能被釋放,當一個對象一句不需要再使用了,本來該被回收時,而有另外一個正在使用的對象持有它的引用從而導致它不能被回收,這導致本該被回收的對象不能被回收而停留在堆內存中,這就產生了內存泄漏(上面的例子就是這個原因)。最終也就造成了OOM.......我們再來段清晰的代碼,我們來使用mHandler發送一個延遲消息:

Android,Handler,內存泄漏

分析:當我們執行了HandlerActivity的界面時,被延遲的消息會在被處理之前存在于主線程消息隊列中5分鐘,而這個消息中又包含了Handler的引用,而我們創建的Handler又是一個匿名內部類的實例,其持有外部HandlerActivity的引用,這將導致了HandlerActivity無法回收,進行導致HandlerActivity持有的很多資源都無法回收,從而就造成了傳說中的內存泄露問題!

2.問題驗證(如果感覺繁瑣請直接跳過)

為了進一步驗證內存泄漏問題,我們在該類中創建一個int數組,該數組分配的內存大小為2m,然后我們用DDMS來查看heap內存,然后使用GC回收,看看內存會不會有變化:

Android,Handler,內存泄漏

第一次啟動app時,head內存為12.5M,已經分配內容(Allocated):8.5M,空閑內存:4M,我們頻繁點擊GC按鈕,內存并沒有發生明顯變化,現在我們點擊手機返回健,推出應用,然后再重新進入,同樣檢測一下head內存:

Android,Handler,內存泄漏

我們發現head內存:20.5M,Allocated:16.5M,Free:4M,堆內存和已經分配內存近乎翻倍,我們繼續頻繁點擊GC, 看看能否被回收?結果內存并沒有明顯變化,現在我們繼續點擊手機返回健,推出應用,然后再重新進入,同樣再次檢測一下head內存:

Android,Handler,內存泄漏

我們發現head內存:28.5M,Allocated:24.5M,Free:4M,堆內存和已經分配內存又增加了,而且無論我們如何點擊GC回收內存,內存都沒有明顯變化,而且每啟動一次該頁面,內存就增加一倍!這也就說存在在某個類只創建而沒銷毀的情況,其實就是存在內存泄漏問題。我們使用MAT工具進一步驗證這個問題,我們來看一組Histogram的數據和dominator tree數據,首先是Histogram的數據:

Android,Handler,內存泄漏

dominator tree數據:

Android,Handler,內存泄漏

同時存在三個一樣的HandlerActivity和內部類,這就足以說明HandlerActvity只有創建沒被銷毀了吧,也就是說Handler造成的內存泄漏真的存在。

3.Handler內存泄漏解決方法

解決這個問題思路就是使用靜態內部類并繼承Handler時(或者也可以單獨存放成一個類文件)。因為靜態的內部類不會持有外部類的引用,所以不會導致外部類實例的內存泄露。當你需要在靜態內部類中調用外部的Activity時,我們可以使用弱引用來處理。另外關于同樣也需要將Runnable設置為靜態的成員屬性。修改后不會導致內存泄露的代碼如下:

package com.zejian.handlerlooper;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.Message;import java.lang.ref.WeakReference;/** * Created by zejian on 16/3/6. */public class HandlerActivity extends Activity { //創建一個2M大小的int數組 int[] datas=new int[1024*1024*2];// Handler mHandler = new Handler(){//  @Override//  public void handleMessage(Message msg) {//   super.handleMessage(msg);//  }// }; /**  * 創建靜態內部類  */ private static class MyHandler extends Handler{  //持有弱引用HandlerActivity,GC回收時會被回收掉.  private final WeakReference<HandlerActivity> mActivty;  public MyHandler(HandlerActivity activity){   mActivty =new WeakReference<HandlerActivity>(activity);  }  @Override  public void handleMessage(Message msg) {   HandlerActivity activity=mActivty.get();   super.handleMessage(msg);   if(activity!=null){    //執行業務邏輯   }  } } private static final Runnable myRunnable = new Runnable() {  @Override  public void run() {   //執行我們的業務邏輯  } }; @Override protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_handler_leak);  MyHandler myHandler=new MyHandler(this);  //解決了內存泄漏,延遲5分鐘后發送  myHandler.postDelayed(myRunnable, 1000 * 60 * 5); }}

Handler的內存泄漏問題到此分析解決完成。其實產生內存泄漏的還有好幾種情況,比如多線程造成的內存泄漏,靜態變量造成的內存泄漏,單例模式造成的內存泄漏等等.......當然這些不在本篇的范圍內,就不過多分析啦。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 巴中市| 平顺县| 宜宾市| 阿合奇县| 曲沃县| 内黄县| 霞浦县| 忻城县| 宜宾县| 南溪县| 石门县| 全州县| 文昌市| 福建省| 柏乡县| 山东| 兴安县| 教育| 枞阳县| 彭水| 淮北市| 镇坪县| 盘锦市| 望谟县| 清河县| 元氏县| 洪洞县| 华安县| 福贡县| 通道| 八宿县| 嵩明县| 平和县| 桐乡市| 元朗区| 诸暨市| 海口市| 承德县| 平邑县| 元谋县| 同仁县|