Android之內(nèi)存溢出和內(nèi)存泄漏的原因和解決方案_第1頁
Android之內(nèi)存溢出和內(nèi)存泄漏的原因和解決方案_第2頁
Android之內(nèi)存溢出和內(nèi)存泄漏的原因和解決方案_第3頁
Android之內(nèi)存溢出和內(nèi)存泄漏的原因和解決方案_第4頁
Android之內(nèi)存溢出和內(nèi)存泄漏的原因和解決方案_第5頁
全文預(yù)覽已結(jié)束

下載本文檔

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

文檔簡介

Android之內(nèi)存溢出和內(nèi)存泄漏的原因和解決方案基礎(chǔ)JAVA是在JVM所虛擬出的內(nèi)存環(huán)境中運(yùn)行的,內(nèi)存分為三個區(qū):堆、棧和方法區(qū)。棧(stack):是簡單的數(shù)據(jù)結(jié)構(gòu),程序運(yùn)行時(shí)系統(tǒng)自動分配,使用完畢后自動釋放。優(yōu)點(diǎn):速度快。堆(heap):用于存放由new創(chuàng)建的對象和數(shù)組。在堆中分配的內(nèi)存,一方面由java虛擬機(jī)自動垃圾回收器來管理,另一方面還需要程序員提供修養(yǎng),防止內(nèi)存泄露問題。方法區(qū)(method):又叫靜態(tài)區(qū),跟堆一樣,被所有的線程共享。方法區(qū)包含所有的class和static變量。概念內(nèi)存溢出(OutofMemory):系統(tǒng)會給每個APP分配內(nèi)存也就是HeapSize值。當(dāng)APP占用的內(nèi)存加上我們申請的內(nèi)存資源超虛擬機(jī)的最大內(nèi)存時(shí)就會拋出的OutOfMemory異常。內(nèi)存泄漏(MemoryLeak):當(dāng)一個對象不在使用了,本應(yīng)該被垃圾回收器(JVM)回收。但是這個對象由于被其他正在使用的有,造成無法被回收的結(jié)果。內(nèi)存泄漏最終會導(dǎo)致內(nèi)存溢出。內(nèi)存抖動:內(nèi)存抖動是指在短時(shí)間內(nèi)有大量的對象被創(chuàng)建或者被回收的現(xiàn)象,主要是循環(huán)中大量創(chuàng)建、回收對象。這種情況應(yīng)當(dāng)盡量避免。它們?nèi)叩闹匾燃壏謩e:內(nèi)存溢出>內(nèi)存泄露>內(nèi)存抖動。內(nèi)存溢出對我們的App來說,影響是非常大的。有可能導(dǎo)致程序閃退,無響應(yīng)等現(xiàn)象,因此,我們一定要優(yōu)先解決OOM的問題。強(qiáng)引用:強(qiáng)引用是使用最普遍的引用。如果一個對象具有強(qiáng)引用,那垃圾回收器絕不會回收它。當(dāng)內(nèi)存空間不足,Java虛擬機(jī)寧愿拋出OutOfMemoryError錯誤,使程序異常終止,也不會靠隨意回收具有強(qiáng)引用的對象來解決內(nèi)存不足的問題。軟引用:如果一個對象只具有軟引用,但內(nèi)存空間足夠時(shí),垃圾回收器就不會回收它;直到虛擬機(jī)報(bào)告內(nèi)存不夠時(shí)才會回收,只要垃圾回收器沒有回收它,該對象就可以被程序使用。軟引用可用來實(shí)現(xiàn)內(nèi)存敏感的高速緩存。軟引用可以和一個引用隊(duì)列(ReferenceQueue)聯(lián)合使用,如果軟引用所引用的對象被垃圾回收器回收,Java虛擬機(jī)就會把這個軟引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。弱引用:只具有弱引用的對象擁有更短暫的生命周期。在垃圾回收器線程掃描它所管轄的內(nèi)存區(qū)域的過程中,一旦發(fā)現(xiàn)了只具有弱引用的對象,不管當(dāng)前內(nèi)存空間是否足夠,都會回收它的內(nèi)存。不過,由于垃圾回收器是一個優(yōu)先級很低的線程,因此不一定會很快發(fā)現(xiàn)那些只具有弱引用的對象。弱引用可以和一個引用隊(duì)列(ReferenceQueue)聯(lián)合使用,如果弱引用所引用的對象被垃圾回收,Java虛擬機(jī)就會把這個弱引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。虛引用:虛引用可以理解為虛設(shè)的引用,與其他幾種引用都不同,虛引用并不會決定對象的生命周期。如果一個對象僅持有虛引用,那么它就和沒有任何引用一樣,在任何時(shí)候都可能被垃圾回收器回收。虛引用主要用來跟蹤對象被垃圾回收器回收的活動。虛引用與軟引用和弱引用的一個區(qū)別在于:虛引用必須和引用隊(duì)列(ReferenceQueue)聯(lián)合使用。當(dāng)垃圾回收器準(zhǔn)備回收一個對象時(shí),如果發(fā)現(xiàn)它還有虛引用,就會在回收對象的內(nèi)存之前,把這個虛引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。程序可以通過判斷引用隊(duì)列中是否已經(jīng)加入了虛引用,來了解被引用的對象是否將要被垃圾回收。如果程序發(fā)現(xiàn)某個虛引用已經(jīng)被加入到引用隊(duì)列,那么就可以在所引用的對象的內(nèi)存被回收之前采取必要的行動。關(guān)系內(nèi)存泄漏是造成應(yīng)用程序OOM的主要原因之一。由于Android系統(tǒng)為每個應(yīng)用程序分配的內(nèi)存有限,當(dāng)一個應(yīng)用中產(chǎn)生的內(nèi)存泄漏比較多時(shí),就難免會導(dǎo)致應(yīng)用所需要的內(nèi)存超過這個系統(tǒng)分配的內(nèi)存限額,這就造成了內(nèi)存溢出而導(dǎo)致應(yīng)用Crash。我們的App多次出現(xiàn)內(nèi)存泄露,可能就會導(dǎo)致內(nèi)存溢出。但是,我們的App出現(xiàn)內(nèi)存溢出,不一定就是因?yàn)閮?nèi)存泄露,因?yàn)楸旧鞟ndroid系統(tǒng)分配給每一個的App的空間就是那么一點(diǎn)。另外,內(nèi)存泄露也不一定就會出現(xiàn)內(nèi)存溢出,因?yàn)檫€是泄露的速度比較慢,系統(tǒng)將進(jìn)程殺死了,也就不會內(nèi)存溢出。不過,發(fā)現(xiàn)內(nèi)存泄露,我們還是要第一時(shí)間解決。危害內(nèi)存溢出:會觸發(fā)Java.Iang.OutOfMemoryError,造成程序崩潰。內(nèi)存泄漏:過多的內(nèi)存泄漏會造成內(nèi)存溢出,同樣也會造成相關(guān)UI的卡頓現(xiàn)象。判斷是否有內(nèi)存泄露的工具LeackCanaryMemoryMonitorDDMS處理方式匯總強(qiáng)引用,軟引用和弱引用釋放強(qiáng)引用,使用軟引用和弱引用;大量的圖片、音頻、視頻處理,當(dāng)在內(nèi)存比較低的系統(tǒng)上也容易造成內(nèi)存溢出建議使用第三方,或者JNI來進(jìn)行處理;Bitmap對象的處理不要在主線程中處理圖片使用Bitmap對象要用recycle釋放//Bitmap對象沒有被回收if(!bitmapObject.isRecyled()){//釋放bitmapObject.recycle();//提醒系統(tǒng)及時(shí)回收System.gc();}控制圖片的大小,壓縮大圖,高效處理,加載合適屬性的圖片。當(dāng)我們有些場景是可以顯示縮略圖的時(shí)候,就不要調(diào)用網(wǎng)絡(luò)請求加載大圖,例如在RecyclerView中,我們在上下滑動的時(shí)候,就不要去調(diào)用網(wǎng)絡(luò)請求,當(dāng)監(jiān)聽到滑動結(jié)束的時(shí)候,才去加載大圖,以免上下滑動的時(shí)候產(chǎn)生卡頓現(xiàn)象。非靜態(tài)內(nèi)部類和匿名內(nèi)部類Handler、Thread、Runnable等由于持有外部類Activity的引用,從而關(guān)閉activity,線程未完成造成內(nèi)存泄漏在Activity中創(chuàng)建非靜態(tài)內(nèi)部類,非靜態(tài)內(nèi)部類會持有Activity的隱式引用,若內(nèi)部類生命周期長于Activity,會導(dǎo)致Activity實(shí)收。(屏幕旋轉(zhuǎn)后會重新創(chuàng)建Activity實(shí)例,如果內(nèi)部類持有引用,將會導(dǎo)致旋轉(zhuǎn)前的實(shí)例無法被回收)。如果一定要使用內(nèi)部類,就改用static內(nèi)部類,在內(nèi)部類中通過WeakReference的方式引用外界資源。對Handler、Thread、Runnable等使用弱引用,并且調(diào)用removeCallbacksAndMessages等移除。舉例:在下面這段代碼中存在一個非靜態(tài)的匿名類對象Thread,會隱式持有一個外部類的引用MainActivity。同理,若是這個Thread作為MainActivity的內(nèi)部類而不是匿名內(nèi)部類,他同樣會持有外部類的引用。publicclassMainActivityextendsAppCompatActivity{@OverrideprotectedvoidonCreate(BundlesavedlnstanceState){super.onCreate(savedlnstanceState);setContentView(R.layout.main);leakFun();}privatevoidleakFun(){newThread(newRunnable(){@Overridepublicvoidrun(){try{Thread.sleep(10*1000);}catch(InterruptedExceptione){e.printStackTrace();}}});}}R;束:jj於薯於於孟jjj;束g芟工嚨吏於薯撈於薯實(shí)jj:直在線程休眠的這10s內(nèi),會一直隱式持有外部類的引用MainActivity,如果在10s之前,銷毀MainActivity,就會報(bào)內(nèi)存泄漏。同理,若是這個Thread作為MainActivity的內(nèi)部類而不是匿名內(nèi)部類,也會內(nèi)存泄漏。總而言之:如果Activity在銷毀之前,任務(wù)還未完成,那么將導(dǎo)致Activity的內(nèi)存資源無法回收,造成內(nèi)存泄漏。解決辦法:在這里只需要將為Thread匿名類定義成靜態(tài)的內(nèi)部類即可(靜態(tài)的內(nèi)部類不會持有外部類的一個隱式引用)?;虮WC在Activity在銷毀之前,完成任務(wù)!在關(guān)閉Activity的時(shí)候停掉你的后臺線程。線程停掉了,就相當(dāng)于切斷了Handler和夕卜部連接的線,Activity自然會在合適的時(shí)候被回收。資源未及時(shí)關(guān)閉造成的內(nèi)存泄漏對于使用了BraodcastReceiver,Contentobserver,Cursor,F(xiàn)ile,Stream,ContentProvider,Bitmap,動畫,1/0,數(shù)據(jù)庫,網(wǎng)絡(luò)的連接等資源的使用,應(yīng)該在Activity銷毀時(shí)及時(shí)關(guān)閉或者注銷,否則這些資源將不會被回收,造成內(nèi)存泄漏。廣播BraodcastReceiver:記得注銷注冊unregisterReceiver();文件流File:記得關(guān)閉流Inputstream/OutputStream.close();數(shù)據(jù)庫游標(biāo)Cursor:使用后關(guān)閉游標(biāo)cursor.close();對于圖片資源Bitmap:當(dāng)它不再被使用時(shí),應(yīng)調(diào)用recycle()回收此對象的像素所占用的內(nèi)存,再賦為null動畫:屬性動畫或循環(huán)動畫,在Activity退出時(shí)需要停止動畫。在屬性動畫中有一類無限循環(huán)動畫,如果在Activity中播放這類動畫并且在onDestroy中沒有去停止動畫,那么這個動畫將會一直播放下去,這時(shí)候Activity會被View所持有,從而導(dǎo)致Activity無法被釋放。在Activity中onDestroy去調(diào)用objectAnimator.cancel()來停止動畫。publicclassLeakActivityextendsAppCompatActivity{privateTextViewtextView;@OverrideprotectedvoidonCreate(BundlesavedlnstanceState){super.onCreate(savedlnstanceState);setContentView(R」ayout.activity_leak);textView=(TextView)findViewByld(R.id.text_view);ObjectAnimatorobjectAnimator=ObjectAnimator.ofFloat(textView,"rotation",0,360);objectAnimator.setRepeatCount(ValueAnimator.lNFINITE);objectAnimator.start();}}集合對象及時(shí)清理,使得JVM回收:我們通常會把對象存入集合中,當(dāng)不使用時(shí),清空集合,讓相關(guān)對象不再被引用;objectList.clear();objectList=null;注銷監(jiān)聽器在onPause()/onDestroy()方法中解除監(jiān)聽器,包括在Android自己的Listener,LocationService或DisplayManager寫的Listener。static關(guān)鍵字修飾的變量由于生命周期過長,容易造成內(nèi)存泄漏static對象的生命周期過長,應(yīng)該謹(jǐn)慎使用。一定要使用要及時(shí)進(jìn)行null處理。靜態(tài)變量Activity和View會導(dǎo)致內(nèi)存泄漏。例如:context,textView實(shí)例的生命周期與應(yīng)用的生命周期一樣,而他們都持有當(dāng)前Activity的(MainActivity)引用,一旦MainActivity銷毀,而他的引用一直被持有,就不會被回收。所以,內(nèi)存泄漏就產(chǎn)出了。publicclassMainActivityextendsAppCompatActivity{privatestaticContextcontext;privatestaticTextViewtextView;@OverrideprotectedvoidonCreate(BundlesavedlnstanceState){super.onCreate(savedlnstanceState);setContentView(R.layout.activity_main);context=this;textView=newTextView(this);}}如果使用Context,盡可能使用Applicaiton的Context單例模式造成的內(nèi)存泄漏,如context的使用,單例中傳入的是activity的context,在關(guān)閉activity時(shí),activity的內(nèi)存無法持有activity的引用。在context的使用上,應(yīng)該傳入application的context到單例模式中,這樣就保證了單例的生命周期跟application的生命周期一樣。因?yàn)閱卫撵o態(tài)特性使得單例的生命周期和應(yīng)用的生命周期一樣長,這就說明了如果一個對象已經(jīng)不需要使用了,而單例對象還持有該對象的引用,那么這個對象將不能被正?;厥眨@就導(dǎo)致了內(nèi)存泄漏。單例模式應(yīng)該盡量少持有生命周期不同的外部對象,一旦持有該對象的時(shí)候,必須在該對象的生命周期結(jié)束前nullpublicclassTestManager{privatestaticTestManagerinstance;privateContextcontext;privateTestManager(Contextcontext){this.context=context;}publicstaticTestManagergetlnstance(Contextcontext){if(instance!=null){instance=newTestManager(context);}returninstance;這是一個普通的單例模式,當(dāng)創(chuàng)建這個單例的時(shí)候,由于需要傳入一個Context,所以這個Context的生命周期的長短至關(guān)重要:1、傳入的是Application的Context:這將沒有任何問題,因?yàn)閱卫纳芷诤虯pplication的一樣長;2、傳入的是Activity的Context:當(dāng)這個Context所對應(yīng)的Activity退出時(shí),由于該Context和Activity的生命周期一樣長(Activity間接繼承于Context),所以當(dāng)前Activity退出時(shí)它的內(nèi)存并不會被回收,因?yàn)閱卫龑ο蟪钟性揂ctivity的引用。所以正確的單例應(yīng)該修改為下面這種方式:publicclassTestManager{privatestaticTestManagerinstance;privateContextcontext;privateTestManager(C

溫馨提示

  • 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)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論