這篇文章將為大家詳細(xì)講解有關(guān)如何解決Android中Handler內(nèi)存泄漏的問(wèn)題,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
成都創(chuàng)新互聯(lián)公司是專業(yè)的吳堡網(wǎng)站建設(shè)公司,吳堡接單;提供網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè),網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行吳堡網(wǎng)站開(kāi)發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛(ài)的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!
在android開(kāi)發(fā)過(guò)程中,我們可能會(huì)遇到過(guò)令人奔潰的OOM異常,面對(duì)這樣的異常我們是既熟悉又深惡痛絕的,因?yàn)樵斐蒓OM的原因有很多種情況,如加載圖片過(guò)大,某已不再使用的類未被GC及時(shí)回收等等......本篇我們就來(lái)分析其中一種造成OOM的場(chǎng)景,它就是罪惡的內(nèi)存泄漏。對(duì)于這樣的稱呼,我們并不陌生,甚至屢次與之"并肩作戰(zhàn)",只不過(guò)它就是一個(gè)豬隊(duì)友,只會(huì)不斷送塔.......
本篇分為3部分:
1.Handler內(nèi)存泄漏例子說(shuō)明以及原理闡明
2.問(wèn)題驗(yàn)證(如果感覺(jué)繁瑣請(qǐng)直接跳過(guò))
3.Handler內(nèi)存泄漏解決方法
1.Handler內(nèi)存泄漏例子說(shuō)明以及原理闡明
Handler,我們已經(jīng)相當(dāng)熟悉了,而且經(jīng)常用得不亦樂(lè)乎,但就是因?yàn)樘煜ち耍艜?huì)偶爾被它反捅一刀,血流不止......還記得我們?cè)?jīng)滿懷信心地使用著如下的優(yōu)美而又簡(jiǎn)潔的代碼不?

不怕你嚇著,實(shí)話告訴你,這個(gè)代碼已經(jīng)造成內(nèi)存泄漏了!!!不相信?我們使用Android lint工具檢測(cè)一下該類的代碼:

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

分析:當(dāng)我們執(zhí)行了HandlerActivity的界面時(shí),被延遲的消息會(huì)在被處理之前存在于主線程消息隊(duì)列中5分鐘,而這個(gè)消息中又包含了Handler的引用,而我們創(chuàng)建的Handler又是一個(gè)匿名內(nèi)部類的實(shí)例,其持有外部HandlerActivity的引用,這將導(dǎo)致了HandlerActivity無(wú)法回收,進(jìn)行導(dǎo)致HandlerActivity持有的很多資源都無(wú)法回收,從而就造成了傳說(shuō)中的內(nèi)存泄露問(wèn)題!
2.問(wèn)題驗(yàn)證(如果感覺(jué)繁瑣請(qǐng)直接跳過(guò))
為了進(jìn)一步驗(yàn)證內(nèi)存泄漏問(wèn)題,我們?cè)谠擃愔袆?chuàng)建一個(gè)int數(shù)組,該數(shù)組分配的內(nèi)存大小為2m,然后我們用DDMS來(lái)查看heap內(nèi)存,然后使用GC回收,看看內(nèi)存會(huì)不會(huì)有變化:

第一次啟動(dòng)app時(shí),head內(nèi)存為12.5M,已經(jīng)分配內(nèi)容(Allocated):8.5M,空閑內(nèi)存:4M,我們頻繁點(diǎn)擊GC按鈕,內(nèi)存并沒(méi)有發(fā)生明顯變化,現(xiàn)在我們點(diǎn)擊手機(jī)返回健,推出應(yīng)用,然后再重新進(jìn)入,同樣檢測(cè)一下head內(nèi)存:

我們發(fā)現(xiàn)head內(nèi)存:20.5M,Allocated:16.5M,Free:4M,堆內(nèi)存和已經(jīng)分配內(nèi)存近乎翻倍,我們繼續(xù)頻繁點(diǎn)擊GC, 看看能否被回收?結(jié)果內(nèi)存并沒(méi)有明顯變化,現(xiàn)在我們繼續(xù)點(diǎn)擊手機(jī)返回健,推出應(yīng)用,然后再重新進(jìn)入,同樣再次檢測(cè)一下head內(nèi)存:

我們發(fā)現(xiàn)head內(nèi)存:28.5M,Allocated:24.5M,Free:4M,堆內(nèi)存和已經(jīng)分配內(nèi)存又增加了,而且無(wú)論我們?nèi)绾吸c(diǎn)擊GC回收內(nèi)存,內(nèi)存都沒(méi)有明顯變化,而且每啟動(dòng)一次該頁(yè)面,內(nèi)存就增加一倍!這也就說(shuō)存在在某個(gè)類只創(chuàng)建而沒(méi)銷毀的情況,其實(shí)就是存在內(nèi)存泄漏問(wèn)題。我們使用MAT工具進(jìn)一步驗(yàn)證這個(gè)問(wèn)題,我們來(lái)看一組Histogram的數(shù)據(jù)和dominator tree數(shù)據(jù),首先是Histogram的數(shù)據(jù):

dominator tree數(shù)據(jù):

同時(shí)存在三個(gè)一樣的HandlerActivity和內(nèi)部類,這就足以說(shuō)明HandlerActvity只有創(chuàng)建沒(méi)被銷毀了吧,也就是說(shuō)Handler造成的內(nèi)存泄漏真的存在。
3.Handler內(nèi)存泄漏解決方法
解決這個(gè)問(wèn)題思路就是使用靜態(tài)內(nèi)部類并繼承Handler時(shí)(或者也可以單獨(dú)存放成一個(gè)類文件)。因?yàn)殪o態(tài)的內(nèi)部類不會(huì)持有外部類的引用,所以不會(huì)導(dǎo)致外部類實(shí)例的內(nèi)存泄露。當(dāng)你需要在靜態(tài)內(nèi)部類中調(diào)用外部的Activity時(shí),我們可以使用弱引用來(lái)處理。另外關(guān)于同樣也需要將Runnable設(shè)置為靜態(tài)的成員屬性。修改后不會(huì)導(dǎo)致內(nèi)存泄露的代碼如下:
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 {
//創(chuàng)建一個(gè)2M大小的int數(shù)組
int[] datas=new int[1024*1024*2];
// Handler mHandler = new Handler(){
// @Override
// public void handleMessage(Message msg) {
// super.handleMessage(msg);
// }
// };
/**
* 創(chuàng)建靜態(tài)內(nèi)部類
*/
private static class MyHandler extends Handler{
//持有弱引用HandlerActivity,GC回收時(shí)會(huì)被回收掉.
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){
//執(zhí)行業(yè)務(wù)邏輯
}
}
}
private static final Runnable myRunnable = new Runnable() {
@Override
public void run() {
//執(zhí)行我們的業(yè)務(wù)邏輯
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_leak);
MyHandler myHandler=new MyHandler(this);
//解決了內(nèi)存泄漏,延遲5分鐘后發(fā)送
myHandler.postDelayed(myRunnable, 1000 * 60 * 5);
}
}Handler的內(nèi)存泄漏問(wèn)題到此分析解決完成。
關(guān)于“如何解決Android中Handler內(nèi)存泄漏的問(wèn)題”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。
本文標(biāo)題:如何解決Android中Handler內(nèi)存泄漏的問(wèn)題
鏈接地址:http://chinadenli.net/article10/jggido.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供虛擬主機(jī)、外貿(mào)網(wǎng)站建設(shè)、響應(yīng)式網(wǎng)站、Google、品牌網(wǎng)站設(shè)計(jì)、手機(jī)網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)