1蓬网、什么是OOM?
程序申請內(nèi)存過大鹉勒,虛擬機無法滿足我們帆锋,然后自殺了。這個現(xiàn)象通常出現(xiàn)在大圖片的APP開發(fā)贸弥,或者需要用到很多圖片的時候窟坐。通俗來講就是我們的APP需要申請一塊內(nèi)存來存放圖片的時候,系統(tǒng)認為我們的程序需要的內(nèi)存過大绵疲,及時系統(tǒng)有充分的內(nèi)存哲鸳,比如1G,但是系統(tǒng)也不會分配給我們的APP盔憨,故而拋出OOM異常徙菠,程序沒有捕捉異常,故而彈窗崩潰了
2郁岩、為什么會有OOM婿奔?
因為Android系統(tǒng)的APP每個進程或者虛擬機有最大內(nèi)存限制,一旦超過這個限制系統(tǒng)就會拋出OOM錯誤问慎。跟手機剩余內(nèi)存是否充足沒有多少關系萍摊。
3、為什么Android會有APP的內(nèi)存限制
(1)要開發(fā)者使用內(nèi)存更加合理如叼。限制每個應用可用內(nèi)存上限冰木,避免惡意程序或單個程序使用過多內(nèi)存導致其他程序的不可運行。有了限制笼恰,開發(fā)者就必須合理使用資源踊沸,優(yōu)化資源使用
(2)屏幕顯示內(nèi)容有限,內(nèi)存足夠即可社证。即使有萬千圖片千萬數(shù)據(jù)需要使用到逼龟,但在特定時刻需要展示給用戶看的總是有限的,因為屏幕顯示就那么大追葡,上面可以放的信息就是很有限的腺律。大部分信息都是處于準備顯示狀態(tài),所以沒必要給予太多heap內(nèi)存宜肉。必須一個ListView顯示圖片疾渣,打個比方這個ListView含有500個item,但是屏幕顯示最多有10調(diào)item顯示崖飘,其余數(shù)據(jù)是處于準備顯示狀態(tài)榴捡。
(3)Android多個虛擬機Davlik的限制需要。android設備上的APP運行朱浴,每打開一個應用就會打開至少一個獨立虛擬機吊圾。這樣可以避免系統(tǒng)崩潰达椰,但代價是浪費更多內(nèi)存。
4项乒、有GC自動回收資源啰劲,為什么還會有OOM?
Android的GC會按照特定的算法來回收不使用的資源檀何,但是gc一般回收的是無主的對象內(nèi)存或者軟引用資源蝇裤。
使用軟引用的圖片資源在一定程度上可以避免OOM。
ps:不用的對象設置為null频鉴,是一個好習慣栓辜。不過更好的方法是,不用的圖片直接recycle垛孔。因為有時候通過設置null讓gc來回收還是來不及藕甩。
5、怎么來避免OOM產(chǎn)生呢周荐?
簡單通過SoftReference引用方式管理圖片資源
建一個SoftReference的hashmap狭莱,使用圖片時,先檢查這個hashmap是否有softreference概作,softreference的圖片是否為空腋妙,如果為空將圖片加載到softreference并加入haspmap。
代碼如下:
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Handler.Callback;
import android.os.Message;
import android.widget.ImageView;
/**
* 功能說明:異步加載圖片
*
*/
public class AsyncImageLoaderCore {
public Context context; // 做本地緩存時會用到
public HashMap<String, SoftReference<Bitmap>> imageCache;// 軟引用集合
public AsyncImageLoaderCore(Context context) {
this.context = context;
this.imageCache = new HashMap<String, SoftReference<Bitmap>>();
}
public Bitmap loadBitmap(final String imageUrl, final ImageView imageView, final ImageCallback imageCallback) {
if (imageCache.containsKey(imageUrl)) {
SoftReference<Bitmap> softReference = imageCache.get(imageUrl);
if (softReference.get() != null)
return softReference.get();
}
final Handler handler = new Handler(new Callback() {
@Override
public boolean handleMessage(Message msg) {
imageCallback.imageLoaded((Bitmap) msg.obj, imageView, imageUrl);
return false;
}
});
new Thread() {
@Override
public void run() {
Bitmap bitmap = null;
try {
bitmap = getHttpBitmap(imageUrl);
} catch (Exception e) {
e.printStackTrace();
return;
}
if (null != bitmap) {
imageCache.put(imageUrl, new SoftReference<Bitmap>(bitmap));
handler.sendMessage(handler.obtainMessage(0, bitmap));
}
}
}.start();
return null;
}
private final int MAX_PIC_LENGTH = 200000;// 最大字節(jié)長度限制[可調(diào),最好不要超過200000]
private final int SAMPLE_SIZE = 14;// 裁剪圖片比列(1/14)[可調(diào)]
/**
* 獲取網(wǎng)絡圖片
*/
private Bitmap getHttpBitmap(String imgUrl) throws Exception {
URL htmlUrl = new URL(imgUrl);
URLConnection connection = htmlUrl.openConnection();
HttpURLConnection conn = (HttpURLConnection) connection;
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
InputStream inputStream = conn.getInputStream();
byte[] bytes = changeToBytes(inputStream);
if (bytes.length < MAX_PIC_LENGTH) {
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
} else if (bytes.length < MAX_PIC_LENGTH * SAMPLE_SIZE) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = false;
options.inSampleSize = SAMPLE_SIZE;
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
}
}
return null;
}
/**
* 將流轉換成字節(jié)數(shù)組
*/
public byte[] changeToBytes(InputStream inputStream) throws Exception
{
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];// 每次讀取的字節(jié)長度
int len = 0;
while ((len = inputStream.read(buffer)) != -1)
{
outputStream.write(buffer, 0, len);
}
inputStream.close();
return outputStream.toByteArray();
}
/**
* 異步加載資源回調(diào)接口
*/
public interface ImageCallback {
public void imageLoaded(Bitmap bitmap, ImageView imageView, String imageUrl);
}
} ```