Android避免內(nèi)存溢出(Out of Memory)方法匯總
避免內(nèi)存溢出的方法,主要是對(duì)以下三個(gè)方面對(duì)程序進(jìn)行優(yōu)化
內(nèi)存引用
在處理內(nèi)存引用之前,我們先來(lái)復(fù)習(xí)下什么是強(qiáng)引用、軟引用、弱引用、虛引用
強(qiáng)引用:強(qiáng)引用是使用最普遍的引用。如果一個(gè)對(duì)象具有強(qiáng)引用,那垃圾回收器絕不會(huì)回收它。 當(dāng)內(nèi)存空間不足,Java虛擬機(jī)寧愿拋出OutOfMemoryError錯(cuò)誤,使程序異常終止,也不會(huì)靠隨意回收具有強(qiáng)引用的對(duì)象來(lái)解決內(nèi)存不足的問(wèn)題。
軟引用:如果一個(gè)對(duì)象只具有軟引用,但內(nèi)存空間足夠時(shí),垃圾回收器就不會(huì)回收它;直到虛擬機(jī)報(bào)告內(nèi)存不夠時(shí)才會(huì)回收, 只要垃圾回收器沒(méi)有回收它,該對(duì)象就可以被程序使用。軟引用可用來(lái)實(shí)現(xiàn)內(nèi)存敏感的高速緩存。 軟引用可以和一個(gè)引用隊(duì)列(ReferenceQueue)聯(lián)合使用,如果軟引用所引用的對(duì)象被垃圾回收器回收,Java虛擬機(jī)就會(huì)把這個(gè)軟引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。
弱引用:只具有弱引用的對(duì)象擁有更短暫的生命周期。在垃圾回收器線程掃描它所管轄的內(nèi)存區(qū)域的過(guò)程中,一旦發(fā)現(xiàn)了只具有弱引用的對(duì)象,不管當(dāng)前內(nèi)存空間是否足夠,都會(huì)回收它的內(nèi)存。 不過(guò),由于垃圾回收器是一個(gè)優(yōu)先級(jí)很低的線程,因此不一定會(huì)很快發(fā)現(xiàn)那些只具有弱引用的對(duì)象。 弱引用可以和一個(gè)引用隊(duì)列(ReferenceQueue)聯(lián)合使用,如果弱引用所引用的對(duì)象被垃圾回收,Java虛擬機(jī)就會(huì)把這個(gè)弱引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。
虛引用:虛引用可以理解為虛設(shè)的引用,與其他幾種引用都不同,虛引用并不會(huì)決定對(duì)象的生命周期。如果一個(gè)對(duì)象僅持有虛引用,那么它就和沒(méi)有任何引用一樣,在任何時(shí)候都可能被垃圾回收器回收。 虛引用主要用來(lái)跟蹤對(duì)象被垃圾回收器回收的活動(dòng)。 虛引用與軟引用和弱引用的一個(gè)區(qū)別在于:虛引用必須和引用隊(duì)列 (ReferenceQueue)聯(lián)合使用。 當(dāng)垃圾回收器準(zhǔn)備回收一個(gè)對(duì)象時(shí),如果發(fā)現(xiàn)它還有虛引用,就會(huì)在回收對(duì)象的內(nèi)存之前,把這個(gè)虛引用加入到與之 關(guān)聯(lián)的引用隊(duì)列中。 程序可以通過(guò)判斷引用隊(duì)列中是否已經(jīng)加入了虛引用,來(lái)了解被引用的對(duì)象是否將要被垃圾回收。 如果程序發(fā)現(xiàn)某個(gè)虛引用已經(jīng)被加入到引用隊(duì)列,那么就可以在所引用的對(duì)象的內(nèi)存被回收之前采取必要的行動(dòng)。
1、釋放強(qiáng)引用
一般我們?cè)诼暶鲗?duì)象變量時(shí),使用完后就不管了,認(rèn)為垃圾回收器會(huì)幫助我們回收這些對(duì)象所指向的內(nèi)存空間,實(shí)際上如果這個(gè)對(duì)象的內(nèi)存空間還處在被引用狀態(tài)的話,垃圾回收器是永遠(yuǎn)不會(huì)回收它的內(nèi)存空間的,只有當(dāng)這個(gè)內(nèi)存空間不被任何對(duì)象引用的時(shí)候,垃圾回收器才會(huì)去回收。
所以我們?cè)谑褂猛陮?duì)象后,可以把對(duì)象置為空,這樣我的垃圾回收器gc就會(huì)在合適的時(shí)候釋放掉為該對(duì)象分配的內(nèi)存空間
Object obj = new Object(); obj = null;
當(dāng)然,在置為空前要確認(rèn)是否不再需要使用該對(duì)象了,如果需要隨時(shí)使用這個(gè)對(duì)象,則不能這么做
2、使用軟引用
在jvm報(bào)告內(nèi)存不足之前會(huì)清除所有的軟引用,這樣的話gc就可以收集到很多軟引用釋放出來(lái)的內(nèi)存空間,從而解決內(nèi)存吃緊的問(wèn)題,避免內(nèi)存溢出,什么時(shí)候被回收取決于gc的算法和gc運(yùn)行時(shí)可用的內(nèi)存大小。
我們可以用SoftReference來(lái)封裝強(qiáng)引用的對(duì)象
String str = "zhuwentao"; // 強(qiáng)引用 SoftReference<String> strSoft = new SoftReference<String>(str); // 使用軟引用封裝強(qiáng)引用
3、使用弱引用
gc收集弱引用對(duì)象的執(zhí)行過(guò)程和軟引用一樣,只是gc不會(huì)根據(jù)內(nèi)存情況來(lái)決定是否回收弱引用的對(duì)象。
String str = "zhuwentao"; // 強(qiáng)引用 WeakReference<String> strWeak = new WeakReference<String>(str); // 使用弱引用封裝強(qiáng)強(qiáng)引用
如果你希望能夠隨時(shí)取得某個(gè)對(duì)象的信息,但又不希望影響該對(duì)象的垃圾回收,則應(yīng)該使用WeakReference來(lái)記住該對(duì)象,而不是使用一般的Reference。
圖像處理
大部分的OOM都是發(fā)生在圖片加載上的,當(dāng)我們加載大圖時(shí),需要特別注意避免OOM的發(fā)生。
處理大圖片時(shí),不管你的手機(jī)內(nèi)存有多大,如果不對(duì)圖片進(jìn)行處理,都有可能會(huì)發(fā)生內(nèi)存溢出問(wèn)題。
因?yàn)锳ndroid系統(tǒng)會(huì)為每一個(gè)應(yīng)用分配一定大小的內(nèi)存,并不會(huì)把整個(gè)系統(tǒng)內(nèi)存全部分給應(yīng)用,所以不管你手機(jī)內(nèi)存多大,對(duì)每個(gè)App來(lái)說(shuō),它能使用的內(nèi)存都是有限的。
這和PC端是有很大的不同,PC端如果內(nèi)存不夠了還可以請(qǐng)求使用虛擬內(nèi)存,而Android系統(tǒng)可沒(méi)這個(gè)機(jī)制。
1、在內(nèi)存中壓縮圖片
裝載大圖片時(shí)需要對(duì)圖片進(jìn)行壓縮,使用等比例壓縮的方法直接在內(nèi)存中處理圖片
Options options = new BitmapFactory.Options(); options.inSampleSize = 5; // 原圖的五分之一,設(shè)置為2則為二分之一 BitmapFactory.decodeFile(myImage.getAbsolutePath(), options);
這樣做要注意的是,圖片質(zhì)量會(huì)變差,inSampleSize設(shè)置的值越大,圖片質(zhì)量就越差,不同的手機(jī)廠商縮放的比例可能不同。
2、使用完圖片后回收?qǐng)D片所占內(nèi)存
由于Android外層是使用java而底層使用的是c語(yǔ)言在里層為圖片對(duì)象分配的內(nèi)存空間。
所以我們的外部雖然看起來(lái)釋放了,但里層卻并不一定完全釋放了,我們使用完圖片后最好再釋放掉里層的內(nèi)存空間。
if (!bitmapObject.isRecyled()) { // Bitmap對(duì)象沒(méi)有被回收 bitmapObject.recycle(); // 釋放 System.gc(); // 提醒系統(tǒng)及時(shí)回收 }
3、降低要顯示的圖片色彩質(zhì)量
Android中Bitmap有四種圖片色彩模式:
ALPHA_8:每個(gè)像素需要占用內(nèi)存中的1byte
RGB_565:每個(gè)像素需要占用內(nèi)存中的2byte
ARGB_4444:每個(gè)像素需要占用內(nèi)存中的2byte
ARGB_8888:每個(gè)像素需要占用內(nèi)存中的4byte
我們創(chuàng)建Bitmap時(shí),默認(rèn)的色彩模式是ARGB_8888的,這種色彩模式是質(zhì)量最高的,當(dāng)然這樣的模式占用的內(nèi)存也最大。
而ARGB_4444每個(gè)像素只占用2byte,所以使用ARGB_4444的模式也能降低圖片占用的內(nèi)存大小。
BitmapFactory.Options options = new BitmapFactory.Options(); options.inPreferredConfig = Bitmap.Config.ARGB_4444; Bitmap btimapObject = BitmapFactory.decodeFile(myImage.getAbsolutePath(), options);
其實(shí)大多數(shù)圖片設(shè)置成ARGB_4444模式后,在顯示上是看不出與ARGB_8888模式有什么差別的,只是在具有漸變色效果的圖片時(shí),可能會(huì)讓漸變色呈現(xiàn)色彩條樣的效果。
這種降低色彩質(zhì)量的方法對(duì)內(nèi)存的降低效果不如方法1明顯。
4、查詢圖片信息時(shí)不把圖片加載到內(nèi)存中
有時(shí)候我們?nèi)〉靡粡垐D片,也許只是為了獲得這個(gè)圖片的一些信息,比如圖片的width、height等信息,不需要顯示到界面上,這個(gè)時(shí)候我們可以不把圖片加載到內(nèi)存中。
BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; // 不把圖片加載到內(nèi)存中 Bitmap btimapObject = BitmapFactory.decodeFile(myImage.getAbsolutePath(), options);
inJustDecodeBounds屬性,如果值為true,那么將不返回實(shí)際的Bitmap對(duì)象,也不給其分配內(nèi)存空間,但允許我們查詢圖片寬、高、大小等基本信息。
(獲取原始寬高:options.outWidth,options.outHeight)
VMRuntime
VMRuntime是Android SDK中提供的一個(gè)類。
只在Android2.3以前有用,2.3以后的SDK就不支持了,所以這個(gè)VMRuntime并不通用。
這里簡(jiǎn)單介紹下就好了。
1、優(yōu)化Dalvik虛擬機(jī)的堆內(nèi)存分配
VMRuntime類提供的setTargetHeapUtilization方法可以增強(qiáng)程序堆內(nèi)存的處理效率。
private final static float TARGET_HEAP_UTILIZATION = 0.75f; VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION);
2、自定義堆內(nèi)存大小
強(qiáng)制定義Android給當(dāng)前App分配的內(nèi)存大小,使用VMRuntime設(shè)置應(yīng)用最小堆內(nèi)存。
// 設(shè)置最小heap內(nèi)存為 6MB 大小 private final static int HEAP_SIZE = 6 * 1024 * 1024 ; VMRuntime.getRuntime().setMinimumHeapSize(HEAP_SIZE);
largeHeap
讓Dalvik虛擬機(jī)為App分配更大的內(nèi)存,該方法能為我們的App爭(zhēng)取到更多內(nèi)存空間,從而緩解內(nèi)存不足的壓力
可以在程序中使用ActivityManager.getMemoryClass()方法來(lái)獲取App內(nèi)存正常使用情況下的大小,通過(guò)ActivityManager.getLargeMemoryClass()可獲得開啟largeHeap時(shí)最大的內(nèi)存大小
1、使用方法
該方法使用非常簡(jiǎn)單,只要在AndroidManifest.xml文件中的<application>節(jié)點(diǎn)屬性中加上”android:largeHeap="true"“
<application android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" android:largeHeap="true"
2、注意
Dalvik為我們App增加的內(nèi)存很可能是通過(guò)殺死其它后臺(tái)進(jìn)程獲取的內(nèi)存,這樣的做法對(duì)于一個(gè)開發(fā)者來(lái)說(shuō)并不道義
我們不應(yīng)該把解決OOM的問(wèn)題寄托在爭(zhēng)取最大的內(nèi)存上,應(yīng)該通過(guò)合理的代碼編寫來(lái)盡可能的規(guī)避OOM問(wèn)題。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android 內(nèi)存溢出和內(nèi)存泄漏的問(wèn)題
- Android 使用幀動(dòng)畫內(nèi)存溢出解決方案
- Android編程內(nèi)存溢出與防范方法淺析
- android 解決ViewPager加載大量圖片內(nèi)存溢出問(wèn)題
- Android編程之內(nèi)存溢出解決方案(OOM)實(shí)例總結(jié)
- Android加載圖片內(nèi)存溢出問(wèn)題解決方法
- android內(nèi)存及內(nèi)存溢出分析詳解
- Android 異步獲取網(wǎng)絡(luò)圖片并處理導(dǎo)致內(nèi)存溢出問(wèn)題解決方法
- Android中Memory Leak原因分析及解決辦法
相關(guān)文章
自定義Toast工具類ToastUtil防止多次點(diǎn)擊時(shí)Toast不消失的方法
下面小編就為大家?guī)?lái)一篇自定義Toast工具類ToastUtil防止多次點(diǎn)擊時(shí)Toast不消失的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04Android手機(jī)衛(wèi)士之設(shè)置密碼對(duì)話框
這篇文章主要為大家詳細(xì)介紹了Android手機(jī)衛(wèi)士之設(shè)置密碼對(duì)話框,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10Android組合式自定義控件實(shí)現(xiàn)購(gòu)物車加減商品操作
這篇文章主要介紹了Android組合式自定義控件實(shí)現(xiàn)購(gòu)物車加減商品操作,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-11-11Android開發(fā)使用Drawable繪制圓角與圓形圖案功能示例
這篇文章主要介紹了Android開發(fā)使用Drawable繪制圓角與圓形圖案功能,結(jié)合具體實(shí)例形式分析了Drawable繪制圓角矩形的實(shí)現(xiàn)步驟與使用方法,需要的朋友可以參考下2017-10-10Android用ActionBar高仿微信主界面的實(shí)例代碼
這篇文章主要介紹了Android用ActionBar高仿微信主界面的實(shí)例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-05-05