【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】Android開(kāi)發(fā)中應(yīng)該避免的內(nèi)存泄露_第1頁(yè)
【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】Android開(kāi)發(fā)中應(yīng)該避免的內(nèi)存泄露_第2頁(yè)
【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】Android開(kāi)發(fā)中應(yīng)該避免的內(nèi)存泄露_第3頁(yè)
【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】Android開(kāi)發(fā)中應(yīng)該避免的內(nèi)存泄露_第4頁(yè)
【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】Android開(kāi)發(fā)中應(yīng)該避免的內(nèi)存泄露_第5頁(yè)
已閱讀5頁(yè),還剩3頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】Android開(kāi)發(fā)中應(yīng)該避免的內(nèi)存泄露

一、背景和目的:目前許多開(kāi)發(fā)人員在Android開(kāi)發(fā)過(guò)程中,較少關(guān)注實(shí)現(xiàn)細(xì)節(jié)和內(nèi)存使用,容易會(huì)造成內(nèi)存泄露,導(dǎo)致程序OOM。本文會(huì)通過(guò)代碼向大家介紹在Android開(kāi)發(fā)過(guò)程中常見(jiàn)的內(nèi)存泄露。二、常見(jiàn)的內(nèi)存泄露代碼1、使用Handler造成的內(nèi)存問(wèn)題在Android開(kāi)發(fā)過(guò)程中,Handler是比較常用的,通過(guò)Handler發(fā)送Message與主線程進(jìn)行通信,Message發(fā)送之后是存儲(chǔ)在MessageQueue中的,有些Message并不是馬上被處理的,在Message中存在一個(gè)Target,是Handler的一個(gè)引用,如果Message在Handler中的存在時(shí)間過(guò)長(zhǎng),會(huì)導(dǎo)致Handler無(wú)法被回收。如果Handler非靜態(tài),則會(huì)導(dǎo)致相關(guān)引用的Activity或者Service不會(huì)回收,所以在處理Hanlder之類(lèi)的內(nèi)部類(lèi)的時(shí)候,應(yīng)該要將Handler定義為靜態(tài)內(nèi)部類(lèi),同樣在使用HandlerThread的時(shí)候也需要注意,我們來(lái)看看代碼:這個(gè)代碼存在泄漏問(wèn)題,因?yàn)镠andlerThread內(nèi)部會(huì)不斷的循環(huán)執(zhí)行,它不會(huì)自己結(jié)束,線程的生命周期超過(guò)了activity生命周期,當(dāng)橫豎屏切換,HandlerThread線程的數(shù)量會(huì)隨著activity重建次數(shù)的增加而增加。我們應(yīng)該在onDestroy時(shí)將線程停止掉:mThread.getLooper().quit();另外,對(duì)于不是HandlerThread的線程,也應(yīng)該確保activity消耗后,線程已經(jīng)終止,可以這樣做:在onDestroy時(shí)調(diào)用mThread.join();2、使用非靜態(tài)內(nèi)部類(lèi)的靜態(tài)實(shí)例

上面的代碼中的sInstance實(shí)例類(lèi)型為靜態(tài)實(shí)例,在第一個(gè)MainActivityact實(shí)例創(chuàng)建時(shí),sInstance會(huì)獲得并一直持有activity的引用。當(dāng)MainAcitivity銷(xiāo)毀后重建,因?yàn)閟Instance持有activity的引用,所以activity是無(wú)法被GC回收的,進(jìn)程中會(huì)存在2個(gè)MainActivity實(shí)例(activity和重建后的MainActivity實(shí)例),這個(gè)activity對(duì)象就是一個(gè)無(wú)用的但一直占用內(nèi)存的對(duì)象,即無(wú)法回收的垃圾對(duì)象。所以,對(duì)于lauchMode不是singleInstance的Activity,應(yīng)該避免在activity里面實(shí)例化其非靜態(tài)內(nèi)部類(lèi)的靜態(tài)實(shí)例。3、在Activity中使用靜態(tài)成員

由于用靜態(tài)成員sBackground緩存了drawable對(duì)象,所以activity加載速度會(huì)加快,但是這樣做是錯(cuò)誤的。因?yàn)樗鼤?huì)導(dǎo)致activity銷(xiāo)毀后無(wú)法被系統(tǒng)回收。label.setBackgroundDrawable函數(shù)調(diào)用會(huì)將label賦值給sBackground的成員變量。上面代碼意味著:sBackground(GCRoot)會(huì)持有TextView對(duì)象,而TextView持有Activiy對(duì)象。所以導(dǎo)致Activity對(duì)象無(wú)法被系統(tǒng)回收。

以上2個(gè)例子的內(nèi)存泄漏都是因?yàn)锳ctivity的引用的生命周期超越了activity對(duì)象的生命周期。也就是常說(shuō)的Context泄漏,想要避免context相關(guān)的內(nèi)存泄漏,需要注意以下幾點(diǎn):l

不要對(duì)activity的context長(zhǎng)期引用(activity的引用的生存周期應(yīng)該和activity的生命周期相同)l

在可以使用application的context的情況下,盡可能使用application的context來(lái)替代和activity相關(guān)的contextl

如果一個(gè)acitivity的非靜態(tài)內(nèi)部類(lèi)的生命周期不受控制,那么我們就應(yīng)該避免這樣使用。4、注冊(cè)某個(gè)對(duì)象后未注銷(xiāo)注冊(cè)廣播接收器、注冊(cè)觀察者等等,比如:在調(diào)用registerReceiver后,若未調(diào)用unregisterReceiver,它會(huì)導(dǎo)致BroadcastReceiver不會(huì)被unregister而導(dǎo)致內(nèi)存泄露,我們經(jīng)常會(huì)看到類(lèi)似下面的代碼:5、集合中對(duì)象沒(méi)清理造成的內(nèi)存泄露我們通常把一些對(duì)象的引用加入到了集合中,當(dāng)我們不需要該對(duì)象時(shí),如果沒(méi)有把它的引用從集合中清理掉,這樣這個(gè)集合就會(huì)越來(lái)越大。如果這個(gè)集合是static的話,如果對(duì)象不斷增大,達(dá)到一定的值的時(shí)候程序就會(huì)OOM

6、資源對(duì)象沒(méi)關(guān)閉造成的內(nèi)存泄露資源性對(duì)象比如(Cursor,F(xiàn)ile文件等)往往都用了一些緩沖,我們?cè)诓皇褂玫臅r(shí)候,應(yīng)該及時(shí)關(guān)閉它們,以便它們的緩沖及時(shí)回收內(nèi)存。它們的緩沖不僅存在于Java虛擬機(jī)內(nèi),還存在于Java虛擬機(jī)外。如果我們僅僅是把它的引用設(shè)置為null,而不關(guān)閉它們,往往會(huì)造成內(nèi)存泄露。因?yàn)橛行┵Y源性對(duì)象,比如SQLiteCursor(在析構(gòu)函數(shù)finalize(),如果我們沒(méi)有關(guān)閉它,它自己會(huì)調(diào)close()關(guān)閉),如果我們沒(méi)有關(guān)閉它,系統(tǒng)在回收它時(shí)也會(huì)關(guān)閉它,但是這樣的效率太低了。因此對(duì)于資源性對(duì)象在不使用的時(shí)候,應(yīng)該立即調(diào)用它的close()函數(shù),將其關(guān)閉掉,然后再置為null.在我們的程序退出時(shí)一定要確保我們的資源性對(duì)象已經(jīng)關(guān)閉。

程序中經(jīng)常會(huì)進(jìn)行查詢數(shù)據(jù)庫(kù)的操作,但是經(jīng)常會(huì)有使用完畢Cursor后沒(méi)有關(guān)閉的情況。如果我們的查詢結(jié)果集比較小,對(duì)內(nèi)存的消耗不容易被發(fā)現(xiàn),只有在長(zhǎng)時(shí)間大量操作的情況下才會(huì)復(fù)現(xiàn)內(nèi)存問(wèn)題,這樣就會(huì)給以后的測(cè)試和問(wèn)題排查帶來(lái)困難和風(fēng)險(xiǎn)。寫(xiě)代碼時(shí),經(jīng)常會(huì)有人忘記調(diào)用close,或者因?yàn)榇a邏輯問(wèn)題狀況導(dǎo)致close未被調(diào)用。錯(cuò)誤的代碼:修正后的代碼:7、一些不良代碼成內(nèi)存壓力有些代碼并不造成內(nèi)存泄露,但是它們或是對(duì)沒(méi)使用的內(nèi)存沒(méi)進(jìn)行有效及時(shí)的釋放,或是沒(méi)有有效的利用已有的對(duì)象而是頻繁的申請(qǐng)新內(nèi)存,對(duì)內(nèi)存的回收和分配造成很大影響的,容易迫使虛擬機(jī)不得不給該應(yīng)用進(jìn)程分配更多的內(nèi)存,增加vm的負(fù)擔(dān),造成不必要的內(nèi)存開(kāi)支。7.1

Bitmap使用不當(dāng)一、需要及時(shí)的銷(xiāo)毀。雖然,系統(tǒng)能夠確認(rèn)Bitmap分配的內(nèi)存最終會(huì)被銷(xiāo)毀,但是由于它占用的內(nèi)存過(guò)多,所以很可能會(huì)超過(guò)Java堆的限制。因此,在用完Bitmap時(shí),要及時(shí)的recycle掉。recycle并不能確定立即就會(huì)將Bitmap釋放掉,但是會(huì)給虛擬機(jī)一個(gè)暗示:“該圖片可以釋放了”。二、需要設(shè)置一定的采樣率。

有時(shí)候,我們要顯示的區(qū)域很小,沒(méi)有必要將整個(gè)圖片都加載出來(lái),而只需要記載一個(gè)縮小過(guò)的圖片,這時(shí)候可以設(shè)置一定的采樣率,那么就可以大大減小占用的內(nèi)存。如下面的代碼:三、巧妙的運(yùn)用軟引用(SoftRefrence)有些時(shí)候,我們使用Bitmap后沒(méi)有保留對(duì)它的引用,因此就無(wú)法調(diào)用Recycle函數(shù)。這時(shí)候巧妙的運(yùn)用軟引用,可以使Bitmap在內(nèi)存不足時(shí)得到有效的釋放。如下:7.2使用Adapter時(shí),沒(méi)有使用緩存的ConvertView以構(gòu)造ListView的BaseAdapter為例,在BaseAdapter中提共了方法:來(lái)向ListView提供每一個(gè)item所需要的view對(duì)象。初始時(shí)ListView會(huì)從BaseAdapter中根據(jù)當(dāng)前的屏幕布局實(shí)例化一定數(shù)量的view對(duì)象,同時(shí)ListView會(huì)將這些view對(duì)象緩存起來(lái)。當(dāng)向上滾動(dòng)ListView時(shí),原先位于最上面的listitem的view對(duì)象會(huì)被回收,然后被用來(lái)構(gòu)造新出現(xiàn)的最下面的listitem。這個(gè)構(gòu)造過(guò)程就是由getView()方法完成的,getView()的第二個(gè)形參ViewconvertView就是被緩存起來(lái)的listitem的view對(duì)象(初始化時(shí)緩存中沒(méi)有view對(duì)象則convertView是null)。由此可以看出,如果我們不去使用convertView,而是每次都在getView()中重新實(shí)例化一個(gè)View對(duì)象的話,即浪費(fèi)時(shí)間,也造成內(nèi)存垃圾,給垃圾回收增加壓力,如果垃圾回收來(lái)不及的話,虛擬機(jī)將不得不給該應(yīng)用進(jìn)程分配更多的內(nèi)存,造成不必要的內(nèi)存開(kāi)支。ListView回收l(shuí)istitem的view對(duì)象的過(guò)程可以查看:android.widget.AbsListView.Java

錯(cuò)誤的代碼:修正示例代碼:

7.3適當(dāng)?shù)氖褂脤?duì)象池不要在經(jīng)常調(diào)用的方法中創(chuàng)建對(duì)象,每次new之后都丟棄

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論