Android編程中避免內(nèi)存泄露的方法總結(jié)
Android的應(yīng)用被限制為最多占用16m的內(nèi)存,至少在T-Mobile G1上是這樣的(當(dāng)然現(xiàn)在已經(jīng)有幾百兆的內(nèi)存可以用了——譯者注)。它包括電話本身占用的和開發(fā)者可以使用的兩部分。即使你沒有占用全部內(nèi)存的打算,你也應(yīng)該盡量少的使用內(nèi)存,以免別的應(yīng)用在運(yùn)行的時(shí)候關(guān)閉你的應(yīng)用。Android能在內(nèi)存中保持的應(yīng)用越多,用戶在切換應(yīng)用的時(shí)候就越快。作為我的一項(xiàng)工作,我仔細(xì)研究了Android應(yīng)用的內(nèi)存泄露問題,大多數(shù)情況下它們是由同一個(gè)錯(cuò)誤引起的,那就是對(duì)一個(gè)上下文(Context)保持了長時(shí)間的引用。
在Android中,上下文(Context)被用作很多操作中,但是大部分是載入和訪問資源。這就是所有的widget都會(huì)在它們的構(gòu)造函數(shù)中接受一個(gè)上下文(Context)參數(shù)。在一個(gè)合格的Android應(yīng)用中,你通常能夠用到兩種上下文(Context):活動(dòng)(Activity)和應(yīng)用(Application)?;顒?dòng)(Activity)通常被傳遞給需要上下文(Context)參數(shù)的類或者方法:
@Override
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this);
label.setText("Leaks are bad");
setContentView(label);
}
這就意味著那個(gè)View有一個(gè)對(duì)整個(gè)活動(dòng)(Activity)的引用并且對(duì)這個(gè)活動(dòng)(Activity)中保持的所有對(duì)象有保持了引用;通常它們包括整個(gè)View的層次和它的所有資源。因此,如果你“泄露”了上下文(Context)(這里“泄露”的意思是你保持了一個(gè)引用并且組織GC收集它),你將造成大量的內(nèi)存泄露。如果你不夠小心的話,“泄露”一整個(gè)活動(dòng)(Activity)是件非常簡單的事情。
當(dāng)屏幕的方向改變時(shí)系統(tǒng)會(huì)默認(rèn)的銷毀當(dāng)前的活動(dòng)(Activity)并且創(chuàng)建一個(gè)新的并且保持了它的狀態(tài)。這樣的結(jié)果就是Android會(huì)從資源中重新載入應(yīng)用的UI?,F(xiàn)在想象一下,你寫了一個(gè)應(yīng)用,有一個(gè)非常大的位圖,并且你并不想在每次旋轉(zhuǎn)時(shí)都重新載入。保留它并且每次旋轉(zhuǎn)不重新加載的最簡單的辦法就是把它保存在一個(gè)靜態(tài)字段上:
private static Drawable sBackground;
@Override
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this);
label.setText("Leaks are bad");
if (sBackground == null) {
sBackground = getDrawable(R.drawable.large_bitmap);
}
label.setBackgroundDrawable(sBackground);
setContentView(label);
}
這段代碼非??欤瑫r(shí)也錯(cuò)的夠離譜。它泄露了當(dāng)?shù)谝淮纹聊唤嵌雀淖儠r(shí)創(chuàng)建的第一個(gè)活動(dòng)(Activity)。當(dāng)一個(gè)Drawable被附加到一個(gè)View,這個(gè)View被設(shè)置為drawable的一個(gè)回調(diào)。在上面的代碼片斷中,這意味著這個(gè)Drawable對(duì)TextView有一個(gè)引用,同時(shí)這個(gè)TextView對(duì)Activity(Context對(duì)象)保持著引用,同時(shí)這個(gè)Activity對(duì)很多對(duì)象又有引用(這個(gè)多少還要看你的代碼了)。
這個(gè)例子是造成Context泄露的最簡單的一個(gè)原因,你可以看一下我們?cè)?a target="_blank" rel="external nofollow" >主屏幕源碼(查看unbindDrawables()方法)中是通過在Activity銷毀時(shí)設(shè)置保存過的Drawable的回調(diào)為空來解決這個(gè)問題的。更為有趣的是,你可以創(chuàng)建一個(gè)context泄露的鏈,當(dāng)然這非常的糟糕。它們可以讓你飛快的用光所有的內(nèi)存。
有兩種簡單的方法可以避免與context相關(guān)的內(nèi)存泄露。最明顯的一個(gè)就是避免在context的自身的范圍外使用它。上面的例子展示了在類內(nèi)部的一個(gè)靜態(tài)的引用和它們對(duì)外部類的間接引用是非常危險(xiǎn)的。第二個(gè)解決方案就是使用Application Context。這個(gè)context會(huì)伴隨你的應(yīng)用而存在,并且不依賴Activity的的生命周期。如果你計(jì)劃保持一個(gè)需要context的長生命周期的對(duì)象,請(qǐng)記得考慮Application對(duì)象。你可以非常方便的通過調(diào)用Context.getApplicationContext() 或者 Activity.getApplication()獲取它。
總之,為了避免涉及到context的內(nèi)存泄露,請(qǐng)記住如下幾點(diǎn):
1.不要對(duì)一個(gè)Activity Context保持長生命周期的引用(一個(gè)對(duì)Activity的引用應(yīng)該與Activity自身的生命周期相同)
2.嘗試使用應(yīng)用上下文(context-application)代替活動(dòng)上下文(context-activity)
3.如果你不能控制它們的生命周期,在活動(dòng)(Activity)中避免使用不是靜態(tài)的內(nèi)部類,使用靜態(tài)類并且使用弱引用到活動(dòng)(Activity)的內(nèi)部。對(duì)于這個(gè)問題的解決方法是使用靜態(tài)的內(nèi)部類與一個(gè)弱引用(WeakReference)的外部類。就像ViewRoot和它的W內(nèi)部類那么實(shí)現(xiàn)的。
4.垃圾回收器對(duì)于內(nèi)存泄露來說并不是百分百保險(xiǎn)的。
- Android 優(yōu)化Handler防止內(nèi)存泄露
- 解決Android使用Handler造成內(nèi)存泄露問題
- 使用Android Studio檢測(cè)內(nèi)存泄露(LeakCanary)
- Android 消息機(jī)制以及handler的內(nèi)存泄露
- 避免 Android中Context引起的內(nèi)存泄露
- Android 中Handler引起的內(nèi)存泄露
- Android垃圾回收機(jī)制解決內(nèi)存泄露問題
- Android中Handler引起的內(nèi)存泄露問題解決辦法
- Android App調(diào)試內(nèi)存泄露之Cursor篇
- 分析Android常見的內(nèi)存泄露和解決方案
相關(guān)文章
Android編程單元測(cè)試實(shí)例詳解(附源碼)
這篇文章主要介紹了Android編程單元測(cè)試,結(jié)合完整實(shí)例形式詳細(xì)分析了Android單元測(cè)試的具體步驟與相關(guān)技巧,并附帶完整實(shí)例代碼供讀者下載參考,需要的朋友可以參考下2015-11-11解決android報(bào)錯(cuò):Intel HAXM is required to run this AVD
這篇文章主要介紹了解決android報(bào)錯(cuò):Intel HAXM is required to run this AVD,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-11-11Android啟動(dòng)頁設(shè)置及動(dòng)態(tài)權(quán)限跳轉(zhuǎn)問題解決
在我遇到這個(gè)實(shí)際問題之前,我一直認(rèn)為啟動(dòng)頁的作用是美化產(chǎn)品,提升軟件逼格。但實(shí)際上,它更重要的是起到了一個(gè)攔截器的作用,這篇文章主要介紹了Android啟動(dòng)頁設(shè)置以及動(dòng)態(tài)權(quán)限跳轉(zhuǎn),需要的朋友可以參考下2022-04-04android開發(fā)之蜂鳴提示音和震動(dòng)提示的實(shí)現(xiàn)原理與參考代碼
蜂鳴提示音和震動(dòng)提示此功能在手機(jī)使用中很實(shí)用,最近在讀zxing項(xiàng)目,學(xué)到了不少東西;我們一起來看看他是怎么做的,感興趣的朋友可以了解下哦2013-01-018種android 對(duì)話框(Dialog)使用方法詳解
這篇文章主要介紹了8種android 對(duì)話框(Dialog)使用方法。感興趣的朋友可以參考一下2016-03-03android滑動(dòng)解鎖震動(dòng)效果的開啟和取消
在4.0的圓環(huán)滑動(dòng)解鎖中,我們點(diǎn)擊下去的時(shí)候會(huì)有震動(dòng)效果,因?yàn)檫@個(gè)控件設(shè)置的震動(dòng)效果沒有綁定設(shè)置中設(shè)置的觸摸振動(dòng)開關(guān)來取消振動(dòng)效果,下邊這個(gè)例子實(shí)現(xiàn)了開啟和取消的方法2013-06-06