版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
【移動應(yīng)用開發(fā)技術(shù)】Android開發(fā)中應(yīng)該避免的內(nèi)存泄露
一、背景和目的:目前許多開發(fā)人員在Android開發(fā)過程中,較少關(guān)注實現(xiàn)細節(jié)和內(nèi)存使用,容易會造成內(nèi)存泄露,導(dǎo)致程序OOM。本文會通過代碼向大家介紹在Android開發(fā)過程中常見的內(nèi)存泄露。二、常見的內(nèi)存泄露代碼1、使用Handler造成的內(nèi)存問題在Android開發(fā)過程中,Handler是比較常用的,通過Handler發(fā)送Message與主線程進行通信,Message發(fā)送之后是存儲在MessageQueue中的,有些Message并不是馬上被處理的,在Message中存在一個Target,是Handler的一個引用,如果Message在Handler中的存在時間過長,會導(dǎo)致Handler無法被回收。如果Handler非靜態(tài),則會導(dǎo)致相關(guān)引用的Activity或者Service不會回收,所以在處理Hanlder之類的內(nèi)部類的時候,應(yīng)該要將Handler定義為靜態(tài)內(nèi)部類,同樣在使用HandlerThread的時候也需要注意,我們來看看代碼:這個代碼存在泄漏問題,因為HandlerThread內(nèi)部會不斷的循環(huán)執(zhí)行,它不會自己結(jié)束,線程的生命周期超過了activity生命周期,當橫豎屏切換,HandlerThread線程的數(shù)量會隨著activity重建次數(shù)的增加而增加。我們應(yīng)該在onDestroy時將線程停止掉:mThread.getLooper().quit();另外,對于不是HandlerThread的線程,也應(yīng)該確保activity消耗后,線程已經(jīng)終止,可以這樣做:在onDestroy時調(diào)用mThread.join();2、使用非靜態(tài)內(nèi)部類的靜態(tài)實例
上面的代碼中的sInstance實例類型為靜態(tài)實例,在第一個MainActivityact實例創(chuàng)建時,sInstance會獲得并一直持有activity的引用。當MainAcitivity銷毀后重建,因為sInstance持有activity的引用,所以activity是無法被GC回收的,進程中會存在2個MainActivity實例(activity和重建后的MainActivity實例),這個activity對象就是一個無用的但一直占用內(nèi)存的對象,即無法回收的垃圾對象。所以,對于lauchMode不是singleInstance的Activity,應(yīng)該避免在activity里面實例化其非靜態(tài)內(nèi)部類的靜態(tài)實例。3、在Activity中使用靜態(tài)成員
由于用靜態(tài)成員sBackground緩存了drawable對象,所以activity加載速度會加快,但是這樣做是錯誤的。因為它會導(dǎo)致activity銷毀后無法被系統(tǒng)回收。label.setBackgroundDrawable函數(shù)調(diào)用會將label賦值給sBackground的成員變量。上面代碼意味著:sBackground(GCRoot)會持有TextView對象,而TextView持有Activiy對象。所以導(dǎo)致Activity對象無法被系統(tǒng)回收。
以上2個例子的內(nèi)存泄漏都是因為Activity的引用的生命周期超越了activity對象的生命周期。也就是常說的Context泄漏,想要避免context相關(guān)的內(nèi)存泄漏,需要注意以下幾點:l
不要對activity的context長期引用(activity的引用的生存周期應(yīng)該和activity的生命周期相同)l
在可以使用application的context的情況下,盡可能使用application的context來替代和activity相關(guān)的contextl
如果一個acitivity的非靜態(tài)內(nèi)部類的生命周期不受控制,那么我們就應(yīng)該避免這樣使用。4、注冊某個對象后未注銷注冊廣播接收器、注冊觀察者等等,比如:在調(diào)用registerReceiver后,若未調(diào)用unregisterReceiver,它會導(dǎo)致BroadcastReceiver不會被unregister而導(dǎo)致內(nèi)存泄露,我們經(jīng)常會看到類似下面的代碼:5、集合中對象沒清理造成的內(nèi)存泄露我們通常把一些對象的引用加入到了集合中,當我們不需要該對象時,如果沒有把它的引用從集合中清理掉,這樣這個集合就會越來越大。如果這個集合是static的話,如果對象不斷增大,達到一定的值的時候程序就會OOM
6、資源對象沒關(guān)閉造成的內(nèi)存泄露資源性對象比如(Cursor,F(xiàn)ile文件等)往往都用了一些緩沖,我們在不使用的時候,應(yīng)該及時關(guān)閉它們,以便它們的緩沖及時回收內(nèi)存。它們的緩沖不僅存在于Java虛擬機內(nèi),還存在于Java虛擬機外。如果我們僅僅是把它的引用設(shè)置為null,而不關(guān)閉它們,往往會造成內(nèi)存泄露。因為有些資源性對象,比如SQLiteCursor(在析構(gòu)函數(shù)finalize(),如果我們沒有關(guān)閉它,它自己會調(diào)close()關(guān)閉),如果我們沒有關(guān)閉它,系統(tǒng)在回收它時也會關(guān)閉它,但是這樣的效率太低了。因此對于資源性對象在不使用的時候,應(yīng)該立即調(diào)用它的close()函數(shù),將其關(guān)閉掉,然后再置為null.在我們的程序退出時一定要確保我們的資源性對象已經(jīng)關(guān)閉。
程序中經(jīng)常會進行查詢數(shù)據(jù)庫的操作,但是經(jīng)常會有使用完畢Cursor后沒有關(guān)閉的情況。如果我們的查詢結(jié)果集比較小,對內(nèi)存的消耗不容易被發(fā)現(xiàn),只有在長時間大量操作的情況下才會復(fù)現(xiàn)內(nèi)存問題,這樣就會給以后的測試和問題排查帶來困難和風險。寫代碼時,經(jīng)常會有人忘記調(diào)用close,或者因為代碼邏輯問題狀況導(dǎo)致close未被調(diào)用。錯誤的代碼:修正后的代碼:7、一些不良代碼成內(nèi)存壓力有些代碼并不造成內(nèi)存泄露,但是它們或是對沒使用的內(nèi)存沒進行有效及時的釋放,或是沒有有效的利用已有的對象而是頻繁的申請新內(nèi)存,對內(nèi)存的回收和分配造成很大影響的,容易迫使虛擬機不得不給該應(yīng)用進程分配更多的內(nèi)存,增加vm的負擔,造成不必要的內(nèi)存開支。7.1
Bitmap使用不當一、需要及時的銷毀。雖然,系統(tǒng)能夠確認Bitmap分配的內(nèi)存最終會被銷毀,但是由于它占用的內(nèi)存過多,所以很可能會超過Java堆的限制。因此,在用完Bitmap時,要及時的recycle掉。recycle并不能確定立即就會將Bitmap釋放掉,但是會給虛擬機一個暗示:“該圖片可以釋放了”。二、需要設(shè)置一定的采樣率。
有時候,我們要顯示的區(qū)域很小,沒有必要將整個圖片都加載出來,而只需要記載一個縮小過的圖片,這時候可以設(shè)置一定的采樣率,那么就可以大大減小占用的內(nèi)存。如下面的代碼:三、巧妙的運用軟引用(SoftRefrence)有些時候,我們使用Bitmap后沒有保留對它的引用,因此就無法調(diào)用Recycle函數(shù)。這時候巧妙的運用軟引用,可以使Bitmap在內(nèi)存不足時得到有效的釋放。如下:7.2使用Adapter時,沒有使用緩存的ConvertView以構(gòu)造ListView的BaseAdapter為例,在BaseAdapter中提共了方法:來向ListView提供每一個item所需要的view對象。初始時ListView會從BaseAdapter中根據(jù)當前的屏幕布局實例化一定數(shù)量的view對象,同時ListView會將這些view對象緩存起來。當向上滾動ListView時,原先位于最上面的listitem的view對象會被回收,然后被用來構(gòu)造新出現(xiàn)的最下面的listitem。這個構(gòu)造過程就是由getView()方法完成的,getView()的第二個形參ViewconvertView就是被緩存起來的listitem的view對象(初始化時緩存中沒有view對象則convertView是null)。由此可以看出,如果我們不去使用convertView,而是每次都在getView()中重新實例化一個View對象的話,即浪費時間,也造成內(nèi)存垃圾,給垃圾回收增加壓力,如果垃圾回收來不及的話,虛擬機將不得不給該應(yīng)用進程分配更多的內(nèi)存,造成不必要的內(nèi)存開支。ListView回收listitem的view對象的過程可以查看:android.widget.AbsListView.Java
錯誤的代碼:修正示例代碼:
7.3適當?shù)氖褂脤ο蟪夭灰诮?jīng)常調(diào)用的方法中創(chuàng)建對象,每次new之后都丟棄
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 《戰(zhàn)略采購管理》課件
- 二項式系數(shù)的性質(zhì)課件
- 結(jié)腸癌手術(shù)案例分析
- 油藏地球物理一體化地震正演軟件ColchisFM介紹
- 工廠證件轉(zhuǎn)讓合同范例
- 消防監(jiān)測合同范例
- 商務(wù)代理合同范例
- 住房押金合同范例
- 鞋類訂貨合同范例
- 團員勞動合同范例
- 課程設(shè)計列車變頻空挪用直流電源系統(tǒng)的設(shè)計
- 物業(yè)保潔新技術(shù)新設(shè)備的應(yīng)用
- 《四川省病案質(zhì)控指標檢查表》填報指南
- 工程洽商記錄表
- 【旅游學(xué)概論課件】旅游資源
- 1.1、供應(yīng)商管理控制流程與風險控制流程圖
- 北師大版九年級數(shù)學(xué)下冊《圓的對稱性》評課稿
- 住宅室內(nèi)裝飾裝修管理辦法課件
- 呼吸系統(tǒng)疾病診療規(guī)范
- 2023年全國乙卷筆試部分講解課件 【高效課堂+精研精講】 高考英語復(fù)習
- 酒店業(yè)輕資產(chǎn)運營模式案例研究
評論
0/150
提交評論