日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國內(nèi)最全I(xiàn)T社區(qū)平臺 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁 > php開源 > 綜合技術(shù) > [置頂] Android內(nèi)存泄漏查找和解決

[置頂] Android內(nèi)存泄漏查找和解決

來源:程序員人生   發(fā)布時間:2016-07-04 16:59:53 閱讀次數(shù):3384次

Android內(nèi)存泄漏查找和解決

目錄:

  1. 內(nèi)存泄漏的概念
  2. 1個內(nèi)存泄漏的例子
  3. Java中”失效”的private修飾符
  4. 回頭看內(nèi)存泄漏例子泄漏的重點(diǎn)
  5. 強(qiáng)援用與弱援用
  6. 解決內(nèi)部類的內(nèi)存泄漏
  7. Context釀成的泄漏
  8. 使用LeakCanary工具查找內(nèi)存泄漏
  9. 總結(jié)

1.內(nèi)存泄漏概念

1.甚么是內(nèi)存泄漏?
用動態(tài)存儲分配函數(shù)動態(tài)開辟的空間,在使用終了后未釋放,結(jié)果致使1直占據(jù)該內(nèi)存單元。直到程序結(jié)束。即所謂的內(nèi)存泄漏。
其實(shí)說白了就是該內(nèi)存空間使用終了以后未回收

2.內(nèi)存泄漏會致使的問題
內(nèi)存泄漏就是系統(tǒng)回收不了那些分配出去但是又不使用的內(nèi)存, 隨著程序的運(yùn)行,可使用的內(nèi)存就會愈來愈少,機(jī)子就會愈來愈卡,直到內(nèi)存數(shù)據(jù)溢出,然后程序就會掛掉,再隨著操作系統(tǒng)也可能無響應(yīng)。

(在我們平時寫利用的進(jìn)程中,可能會無意的寫了1些存在內(nèi)存泄漏的代碼,如果沒有專業(yè)的工具,對內(nèi)存泄漏的原理也不熟習(xí),要查內(nèi)存泄漏出現(xiàn)在哪里是比較困難的)接下來先看1個內(nèi)存泄漏的例子

2.內(nèi)存泄漏的例子

內(nèi)存泄漏例子1

這個例子存在的問題應(yīng)當(dāng)很容易能看出來,使用了handler延遲1定時間履行Runnable代碼塊,而在Activity結(jié)束的時候又沒有釋放履行的代碼塊,致使了內(nèi)存泄漏。那末只要在Activity結(jié)束onDestroy的時候,釋放延遲履行的代碼塊不就能夠了,確切是,那末再看1看下面的例子。

內(nèi)存泄漏例子2

這段代碼是實(shí)際開發(fā)中存在內(nèi)存泄漏的實(shí)例,略微進(jìn)行簡化得到的。內(nèi)存泄漏的關(guān)鍵點(diǎn)在哪里,怎樣去解決,先留著這個問題,看下面1節(jié)的內(nèi)容:”失效”的private修飾符。

3.Java中”失效”的private修飾符

相信大家都用過內(nèi)部類,Java允許在1個類里面定義另外一個類,類里面的類就是內(nèi)部類,也叫做嵌套類。1個簡單的內(nèi)部類實(shí)現(xiàn)可以以下

class OuterClass { class InnerClass{ } }

下面回頭看上面寫的例子:

內(nèi)存泄漏例子1

這實(shí)際上是1個我們在編程中常常用到的場景,就是在1個內(nèi)部類里面訪問外部類的private成員變量或方法,這是可以的。
這是為何,不是private修飾的成員只能被成員所述的類才能訪問么?難道private真的失效了么?
實(shí)際上是編譯器幫我們做了1些我們看不到的工作,下面我們通過反編譯把這些看不到的工作都扒出來看看


反編譯后

1.下面這1份是通過 dex2jar + jad 進(jìn)行反編譯得到的近似源碼的java類

反編譯源碼1

可以看到這份反編譯出來的代碼,比我們編寫的源碼,要多了1些東西,在內(nèi)部類MyRunnable里面多了1個MainActivity的成員變量,并且,在構(gòu)造函數(shù)里面取得了外部類的援用。

2.再看看下面這1份文件,這是通過 apktool 反編譯出來的 smali指令語言
在這里MainActivity分成了兩個文件,分別是MainActivity.smaliMainActivity$MyRunnable.smali。下面貼出的兩份文件比較長,簡單閱讀1遍便可,詳細(xì)看下面的解析,了解這份文件跟源碼的對應(yīng)關(guān)系。

MainActivity:

.class public Lcom/gexne/car/leaktest/MainActivity; .super Landroid/app/Activity; .source "MainActivity.java" # annotations .annotation system Ldalvik/annotation/MemberClasses; value = { Lcom/gexne/car/leaktest/MainActivity$MyRunnable; } .end annotation # instance fields .field private handler:Landroid/os/Handler; .field private test:Ljava/lang/String; # direct methods .method public constructor <init>()V .locals 1 .prologue .line 18 invoke-direct {p0}, Landroid/app/Activity;-><init>()V .line 20 const-string v0, "TEST_STR" iput-object v0, p0, Lcom/gexne/car/leaktest/MainActivity;->test:Ljava/lang/String; .line 21 new-instance v0, Landroid/os/Handler; invoke-direct {v0}, Landroid/os/Handler;-><init>()V iput-object v0, p0, Lcom/gexne/car/leaktest/MainActivity;->handler:Landroid/os/Handler; return-void .end method .method static synthetic access$000(Lcom/gexne/car/leaktest/MainActivity;)Ljava/lang/String; .locals 1 .param p0, "x0" # Lcom/gexne/car/leaktest/MainActivity; .prologue .line 18 iget-object v0, p0, Lcom/gexne/car/leaktest/MainActivity;->test:Ljava/lang/String; return-object v0 .end method # virtual methods .method protected onCreate(Landroid/os/Bundle;)V .locals 4 .param p1, "savedInstanceState" # Landroid/os/Bundle; .prologue .line 32 invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V .line 33 const/high16 v0, 0x7f040000 invoke-virtual {p0, v0}, Lcom/gexne/car/leaktest/MainActivity;->setContentView(I)V .line 34 iget-object v0, p0, Lcom/gexne/car/leaktest/MainActivity;->handler:Landroid/os/Handler; new-instance v1, Lcom/gexne/car/leaktest/MainActivity$MyRunnable; invoke-direct {v1, p0}, Lcom/gexne/car/leaktest/MainActivity$MyRunnable;-><init>(Lcom/gexne/car/leaktest/MainActivity;)V const-wide/16 v2, 0x2710 invoke-virtual {v0, v1, v2, v3}, Landroid/os/Handler;->postDelayed(Ljava/lang/Runnable;J)Z .line 36 invoke-virtual {p0}, Lcom/gexne/car/leaktest/MainActivity;->finish()V .line 37 return-void .end method

在上面MainActivity.smali文件中,可以看到.field代表的是成員變量,.method代表的是方法,2個成員變量分別是Handler和String,方法則有3個分別是構(gòu)造函數(shù)、onCreate()、access$000()。
嗯?在MainActivity中我們并沒有定義access$000()這類方法,它是1個靜態(tài)方法,接收1個MainActivity實(shí)例作為參數(shù),并且返回MainActivity的test成員變量,所以,它出現(xiàn)的目的就是為了得到MainActivity的私有屬性。

MainActivity$MyRunnable.smali:

.class Lcom/gexne/car/leaktest/MainActivity$MyRunnable; .super Ljava/lang/Object; .source "MainActivity.java" # interfaces .implements Ljava/lang/Runnable; # annotations .annotation system Ldalvik/annotation/EnclosingClass; value = Lcom/gexne/car/leaktest/MainActivity; .end annotation .annotation system Ldalvik/annotation/InnerClass; accessFlags = 0x0 name = "MyRunnable" .end annotation # instance fields .field final synthetic this$0:Lcom/gexne/car/leaktest/MainActivity; # direct methods .method constructor <init>(Lcom/gexne/car/leaktest/MainActivity;)V .locals 0 .param p1, "this$0" # Lcom/gexne/car/leaktest/MainActivity; .prologue .line 23 iput-object p1, p0, Lcom/gexne/car/leaktest/MainActivity$MyRunnable;->this$0:Lcom/gexne/car/leaktest/MainActivity; invoke-direct {p0}, Ljava/lang/Object;-><init>()V return-void .end method # virtual methods .method public run()V .locals 2 .prologue .line 26 const-string v0, "test" iget-object v1, p0, Lcom/gexne/car/leaktest/MainActivity$MyRunnable;->this$0:Lcom/gexne/car/leaktest/MainActivity; # getter for: Lcom/gexne/car/leaktest/MainActivity;->test:Ljava/lang/String; invoke-static {v1}, Lcom/gexne/car/leaktest/MainActivity;->access$000(Lcom/gexne/car/leaktest/MainActivity;)Ljava/lang/String; move-result-object v1 invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I .line 27 return-void .end method

MyRunnable.smali文件中用一樣的方法視察,發(fā)現(xiàn)多了1個成員變量MainActivity,方法分別是構(gòu)造函數(shù)、run(),根據(jù)smali指令的含義可以看到構(gòu)造函數(shù)是接收了1個MainActivity作為參數(shù)的,而run()方法中獲得外部類中的test變量,則是調(diào)用access$000()方法獲得。如果想了解smali指令語言可以自行g(shù)oogle,這里不詳細(xì)講授。通過上面兩個文件,重新還原1下源碼。

復(fù)原反編譯代碼

這段代碼基本上還原了編譯器編譯后指令的履行方式。內(nèi)部類調(diào)用外部類,是通過1個外部類的援用進(jìn)行調(diào)用的(上面紅色框框的兩段代碼是在還原的基礎(chǔ)上加入的,用于解釋內(nèi)部類調(diào)用外部類的方式,調(diào)用方式1是我們經(jīng)常使用的,而到的編譯器編譯后,實(shí)際調(diào)用方式是2),而外部類的private屬性則通過編譯器生成的我們看不見的靜態(tài)方法,通過傳入外部類實(shí)例援用獲得出來。
通過還原,我們了解了非靜態(tài)內(nèi)部類跟外部類交互時的工作方式,和非靜態(tài)內(nèi)部類為何會持有外部類的援用。

參考資料:
1. 細(xì)話Java:”失效”的private修飾符
2. smali語法簡析

4.通過dumpsys查看內(nèi)存使用情況

繼續(xù)回頭看第1個內(nèi)存泄漏的例子,略微進(jìn)行修改

查看內(nèi)存泄漏1

對這段代碼,它會造成內(nèi)存泄漏,那末對外部類Activity來講,它能夠被釋放嗎?
我們通過dumpsys來查看,了解怎樣查看利用的內(nèi)存使用情況,怎樣看1個Activity有無被順利釋放掉,而這個Activity能不能被回收。


1.先創(chuàng)建1個空Activity,以下代碼所示,并安裝到裝備中

public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }

2.通過adb shell dumpsys meminfo <packageName>來查看內(nèi)存使用狀態(tài)
在沒有打開利用的情況下,該命令返回的數(shù)據(jù)是這樣的:
dumpsys未打開應(yīng)用

3.打開這個利用的MainActivity,再通過命令查看:
這里寫圖片描述

可以看到打印出來很多的信息,而對我們查看Activity內(nèi)存泄漏來講,只需要關(guān)注Activities和Views兩個信息便可,在利用中存在的Activity對象有1個,存在的View對象有13個。

4.這時候候我們退出這個Activity,在用命令查看1下:
這里寫圖片描述

可以看到,Activity對象和View對象都在極短的時間內(nèi)被回收掉了。再次打開,退出,屢次嘗試,發(fā)現(xiàn)情況都是1樣的。我們可以通過這類方式來簡單判斷1個Activity是不是存在內(nèi)存泄漏,最后是不是能夠被回收。

5.再運(yùn)行剛才的泄漏的例子,用命令查看1下:
這里寫圖片描述

當(dāng)我們連續(xù)打開退出同1個頁面,然后使用命令查看時,發(fā)現(xiàn)Activity存在13個,而View則存在了234個,而且沒有很快被回收,順次判斷應(yīng)當(dāng)是存在內(nèi)存泄漏了。
等待10多秒,再次查看,發(fā)現(xiàn)Activity和View的數(shù)量都變成了0。
這里寫圖片描述
所以,結(jié)論是能夠被回收,只要Runnable代碼塊履行終了,釋放了Activity的援用,Activity就可以被回收。


上面的例子,是Handler臨時性內(nèi)存泄漏,只要Handler post的代碼塊履行終了,被援用的Activity就可以夠釋放。
除臨時性內(nèi)存泄漏,還有危害更大,直到程序結(jié)束才能被釋放的內(nèi)存泄漏。例如:
這里寫圖片描述

內(nèi)存泄漏例子2
對第1個例子,比較容易看出來,MyRunnable內(nèi)部類持有了Activity的援用,而它本身1直不釋放,致使Activity也1直沒法釋放,使用dumpsys meminfo查看可以驗(yàn)證,屢次打開后退Activities的數(shù)量只會增加不會減少,直得手動結(jié)束全部利用。
而第2個例子也不難看出,只是援用鏈略微長了點(diǎn),TelephonyManager注冊了內(nèi)部類PhoneStateListener,持有了這個內(nèi)部類的援用,PhoneStateListener持有了ViewHolder的援用,ViewHolder同時也是1個內(nèi)部類,持有了ViewAdapter的援用,而ViewAdapter則持有了Activity的援用,最后TelephonyManager又沒有做反注冊的操作,致使了內(nèi)存泄漏。
很多時候我們寫代碼,都疏忽了釋放工作,特別是寫Java寫多了,都覺得這些資源會自動釋放,不用寫釋放方法,不用操心去做釋放工作,然后內(nèi)存泄漏就這樣出現(xiàn)了。

參考資料:
1. 使用meminfo分析Android單個進(jìn)程內(nèi)存信息

5.強(qiáng)援用與弱援用

看完上面的例子,了解到非靜態(tài)內(nèi)部類由于持有外部類的援用,極可能會造成泄漏。為何持有了外部類的援用會致使外部類不能被回收?

在解決內(nèi)存泄漏之前,先了解Java的援用方式。Java有4種援用方式,分別是強(qiáng)援用、弱援用、虛援用、軟援用。這里只介紹強(qiáng)援用和弱援用,更詳細(xì)的資料可以自行查找。


1.強(qiáng)援用(Strong Reference),就是我們常常使用的援用,寫法以下

StringBuffer buffer = new StringBuffer();

上面創(chuàng)建了1個StringBuffer對象,并將這個對象的(強(qiáng))援用存到變量buffer中。強(qiáng)援用最重要的就是它能夠讓援用變得強(qiáng)(Strong),這就決定了它和垃圾回收器的交互。具體來講,如果1個對象可以從GC Roots通過強(qiáng)援用到達(dá)時,那末這個對象將不會被GC回收。

2.弱援用(Weak Reference),弱援用簡單來講就是將對象留在內(nèi)存的能力不是那末強(qiáng)的援用。使用WeakReference,垃圾回收器會幫你來決定援用的對象什么時候回收并且將對象從內(nèi)存移除。創(chuàng)建弱援用以下

WeakReference<Widget> weakWidget = new WeakReference<Widget>(widget);

使用weakWidget.get()就能夠得到真實(shí)的Widget對象,由于弱援用不能阻擋垃圾回收器對其回收,你會發(fā)現(xiàn)(當(dāng)沒有任何強(qiáng)援用到widget對象時)使用get時突然返回null,所以對弱援用要記得做判空處理后再使用,否則很容易出現(xiàn)NPE異常。

參考資料:
1. GC Roots
2. 理解Java中的弱援用

6.解決內(nèi)部類的內(nèi)存泄漏

通過上面介紹的內(nèi)容,我們了解到內(nèi)存泄漏產(chǎn)生的緣由是對象在生命周期結(jié)束時被另外一個對象通過強(qiáng)援用持有而沒法釋放釀成的

怎樣解決這個問題,思路就是避免使用非靜態(tài)內(nèi)部類,定義內(nèi)部類時,要末是放在單獨(dú)的類文件中,要末就是使用靜態(tài)內(nèi)部類。由于靜態(tài)的內(nèi)部類不會持有外部類的援用,所以不會致使外部類實(shí)例的內(nèi)存泄漏。當(dāng)你需要在靜態(tài)內(nèi)部類中調(diào)用外部的Activity時,我們可使用弱援用來處理。
這里寫圖片描述

這類解決方法,對臨時性內(nèi)存泄漏適用,其中包括但不限于自定義動畫的更新回調(diào),網(wǎng)絡(luò)要求數(shù)據(jù)后更新頁面的回調(diào)等,更具體1點(diǎn)的例子有當(dāng)我們在頁面觸發(fā)了網(wǎng)絡(luò)要求加載時,希望它把數(shù)據(jù)加載終了,當(dāng)加載終了時如果頁面還在活動狀態(tài)則更新顯示內(nèi)容。其實(shí)在Android中很多的內(nèi)存泄漏都是由于在Activity中使用了非靜態(tài)內(nèi)部類致使的,所以當(dāng)我們使用時要非靜態(tài)內(nèi)部類時要格外注意。

在Android Studio里面,當(dāng)你定義1個內(nèi)部類Handler的時候,會出現(xiàn)貼心提示,This Handler class should be static or leaks might occur,提示你把Handler改成靜態(tài)類。

這里寫圖片描述


解決了上面的內(nèi)存泄漏問題,再看看下面這個例子:
這里寫圖片描述

這個例子改寫成靜態(tài)內(nèi)部類+弱援用,其實(shí)不能完全解決內(nèi)存泄漏的問題。
為何?只需要加上1句Log便可驗(yàn)證。
這里寫圖片描述

屢次進(jìn)入退出頁面,看1下打印出來的Log
這里寫圖片描述

結(jié)果不言而喻,Log愈來愈多了,雖然Activity最后能夠回收,但只是由于弱援用很弱,GC能夠在內(nèi)存不足的時候回收它,但并沒有完全解決泄漏問題。

使用dumsys meminfo一樣可以驗(yàn)證,每次打開Activity并退出,等GC回收掉Activity后,發(fā)現(xiàn)Local Binder的數(shù)量并沒有減少,而且比上1次多了1。
這里寫圖片描述

對注冊到服務(wù)中的回調(diào)(包括系統(tǒng)服務(wù),自定義服務(wù)),使用靜態(tài)內(nèi)部類+弱援用的方式只能部份解決內(nèi)存泄漏問題,這類問題需要釋放資源時進(jìn)行反注冊才能根本解決,由于這類服務(wù)會長時間存在系統(tǒng)中,注冊了的callback對象會1直存在于服務(wù)中,每次callback來了都會履行callback中的代碼塊,只不過履行到弱援用部份由于弱援用獲得到的對象為null而不會履行下1步操作。例如Broadcast,例如systemServer.listen等。

參考資料:
1. Android中Handler引發(fā)的內(nèi)存泄漏

7.Context釀成的泄漏

了解完內(nèi)部類的泄漏和修復(fù)方法,再來看1下另外一種泄漏,由context釀成的泄漏。
這里寫圖片描述

這也是1個開發(fā)中的例子,稍作修改得到。

可以看到,藍(lán)色框框內(nèi)是1個標(biāo)準(zhǔn)的懶漢式單例。單例是我們比較簡單經(jīng)常使用的1種設(shè)計模式,但是如果單例使用不當(dāng)也會致使內(nèi)存泄漏。比如這個例子,DashBoardTypeface需要持有1個Context作為成員變量,并且使用該Context創(chuàng)建字體資源。
instance作為靜態(tài)對象,其生命周期要擅長普通的對象,其中也包括Activity,當(dāng)我們退出Activity,默許情況下,系統(tǒng)會燒毀當(dāng)前Activity,然后當(dāng)前的Activity被1個單例持有,致使垃圾回收器沒法進(jìn)行回收,進(jìn)而產(chǎn)生了內(nèi)存泄漏。

解決的方法就是不持有Activity的援用,而是持有Application的Context援用。

這里寫圖片描述

在任何使用到Context的地方,都要多加注意,例如我們常見的Dialog,Menu,懸浮窗,這些控件都需要傳入Context作為參數(shù)的,如果要使用Activity作為Context參數(shù),那末1定要保證控件的生命周期跟Activity的生命周期同步。窗體泄漏也是內(nèi)存泄漏的1種,就是我們常見的leak window,這類毛病就是依賴Activity的控件生命周期跟Activity不同步釀成的。

1般來講,對非控件類型的對象需要Context參數(shù),最好優(yōu)先斟酌全局ApplicationContext,來避免內(nèi)存泄漏。

參考資料:
1. 避免Android中Context引發(fā)的內(nèi)存泄漏

8.使用LeakCanary工具查找內(nèi)存泄漏

LeakCanary是甚么?它是1個傻瓜化并且可視化的內(nèi)存泄漏分析工具。

它的特點(diǎn)是簡單,易于發(fā)現(xiàn)問題,人人都可參與,只要配置完成,簡單的黑盒測試通過手工點(diǎn)擊就可以夠看到詳細(xì)的泄漏路徑。

下面來看1下如何集成:

dependencies { debugCompile 'com.squareup.leakcanary:leakcanary-android:1.4-beta2' releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta2' testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta2' }

創(chuàng)建Application并加入LeakCanary代碼:

public class ExampleApplication extends Application { @Override public void onCreate() { super.onCreate(); LeakCanary.install(this); } }

這樣已完成最簡單的集成,可以開始進(jìn)行測試了。
在進(jìn)行嘗試之前再看1段代碼:

這里寫圖片描述

思考完這段代碼的問題后,我們來嘗試1下使用LeakCanary尋覓問題。如上面的配置,配置好利用,安裝后可以看到,利用多了1個入口,如圖所示。

這里寫圖片描述

這個入口就是當(dāng)利用在使用進(jìn)程中產(chǎn)生內(nèi)存泄漏,可以從這個入口看到詳細(xì)的泄漏位置。

這里寫圖片描述

從LeakCanary給出來的分析能輕易找到內(nèi)存泄漏出現(xiàn)在responseHandler里面,跟剛才思考分析的答案是不是1致呢?如果1致那你對內(nèi)存泄漏的知識已掌握很多了。


上面這類是最簡單的默許配置,只對Activity進(jìn)行了檢測。但需要檢測的對象肯定不只有Activity,例如Fragment、Service、Broadcast。這需要做更多的配置,在Application中留下RefWatcher的援用,使用它來檢測其他對象。

public class MyApplication extends Application { private static RefWatcher sRefWatcher; @Override public void onCreate() { super.onCreate(); sRefWatcher = LeakCanary.install(this); } public static RefWatcher getRefWatcher() { return sRefWatcher; } }

在有生命周期的對象的onDestroy()中進(jìn)行監(jiān)控,例如Service。

public class CoreService extends Service { @Override public void onDestroy() { super.onDestroy(); MyApplication.getRefWatcher().watch(this); } }

監(jiān)控需要設(shè)置在對象(很快)被釋放的時候,如Activity和Fragment的onDestroy方法。

1個毛病示例,比如監(jiān)控1個Activity,放在onCreate就會大錯特錯了,那末你每次都會收到Activity的泄漏通知。

更詳細(xì)的資料可以到LeakCanary的github倉庫中查看。

參考資料:
1. Android內(nèi)存泄漏檢測利器:LeakCanary
2. LeakCanary

9.總結(jié)

關(guān)于內(nèi)存泄漏的知識,如何定位內(nèi)存泄漏,如何修復(fù),已講授完了。
最后做1個總結(jié):

場景

  • 非靜態(tài)內(nèi)部類的靜態(tài)實(shí)例
    非靜態(tài)內(nèi)部類會保持1個到外部類實(shí)例的援用,如果非靜態(tài)內(nèi)部類的實(shí)例是靜態(tài)的,就會間接長時間保持著外部類的援用,禁止被回收掉。
  • 資源對象未關(guān)閉
    資源性對象如Cursor、File、Socket,應(yīng)當(dāng)在使用后及時關(guān)閉。未在finally中關(guān)閉,會致使異常情況下資源對象未被釋放的隱患。
  • 注冊對象未反注冊
    未反注冊會致使視察者列表里保持著對象的援用,禁止垃圾回收。
  • Handler臨時性內(nèi)存泄漏
    Handler通過發(fā)送Message與主線程交互,Message發(fā)出以后是存儲在MessageQueue中的,有些Message也不是馬上就被處理的。在Message中存在1個 target,是Handler的1個援用,如果Message在Queue中存在的時間越長,就會致使Handler沒法被回收。如果Handler是非靜態(tài)的,則會致使Activity或Service不會被回收。
    由于AsyncTask內(nèi)部也是Handler機(jī)制,一樣存在內(nèi)存泄漏的風(fēng)險。
    此種內(nèi)存泄漏,1般是臨時性的。

預(yù)防

  • 不要保持到Activity的久長援用,對activity的援用應(yīng)當(dāng)和activity本身有相同的生命周期。
  • 盡可能使用context-application代替context-activity
  • Activity中盡可能不要使用非靜態(tài)內(nèi)部類,可使用靜態(tài)內(nèi)部類和WeakReference代替。

參考資料:
1. Android內(nèi)存泄漏研究

生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 中文字幕一区二区三区在线视频 | 天天摸天天干 | a色网站| 日韩一区二区三区av | 看全色黄大色黄大片女图片第一次 | 久久精品久久久 | 亚洲第一区国产精品 | 欧美亚洲成人网 | 天天操夜夜摸 | 日韩一区二区精品视频 | 日本国产一区二区 | 黄色大片电影 | 午夜精品久久久久久久久久蜜桃 | 久久久精品久久久久 | 久久久久国产一区 | 免费黄色av网站 | 久久黄色一级电影 | 亚洲国产黄色片 | 日韩一区二区成人 | 成人免费毛片片v | 欧美日韩aaa | 狠狠躁日日躁夜夜躁影院 | 亚洲成人福利 | 欧美三区在线观看 | 国产婷婷色一区二区三区在线 | 欧美日韩在线观看视频 | 色婷婷综合久久久中文字幕 | 亚洲视频在线视频观看视频在线 | 成人在线观看视频网站 | 亚洲电影中文字幕 | 国产乱码精品一区二区三区五月婷 | 日本特黄a级高清免费大片 韩国精品久久久 | 天堂成人网 | 久久精品国产精品亚洲 | 亚洲精品免费在线观看 | 国产一区二区三区视频播放 | 日韩精品久久 | 国产精品久久久久久网站 | √新版天堂资源在线资源 | 视频在线国产 | 日韩国产|