天天看點

android 記憶體溢出解決方法,android記憶體溢出解決

1,解決使用Bitmap時出現的記憶體溢出

1)及時的銷毀,雖然,系統能夠确認Bitmap配置設定的記憶體最終會被銷毀,但是由于它占用的記憶體過多,是以很可能會超過java堆的限制。是以,在用完Bitmap時,要及時的recycle掉。recycle并不能确定立即就會将Bitmap釋放掉,但是會給虛拟機一個暗示:“該圖檔可以釋放了”。

2)設定一定的采樣率,有時候,我們要顯示的區域很小,沒有必要将整個圖檔都加載出來,而隻需要記載一個縮小過的圖檔,這時候可以設定一定的采樣率,那麼就可以大大減小占用的記憶體。如下面的代碼:

private ImageView preview;

BitmapFactory.Options options = new BitmapFactory.Options();

options.inSampleSize = 2;

Bitmap bitmap = BitmapFactory.decodeStream(cr.openInputStream(uri),

null, options);

preview.setImageBitmap(bitmap);

3)運用軟引用(SoftRefrence),有些時候,我們使用Bitmap後沒有保留對它的引用,是以就無法調用Recycle函數。這時候巧妙的運用軟引用,可以使Bitmap在記憶體快不足時得到有效的釋放。如下例:

private class MyAdapter extends BaseAdapter {

private ArrayList mBitmapRefs = new ArrayList();

private ArrayList mValues;

private Context mContext;

private LayoutInflater mInflater;

MyAdapter(Context context, ArrayList values) {

mContext = context;

mValues = values;

mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

}

public int getCount() {

return mValues.size();

}

public Object getItem(int i) {

return mValues.get(i);

}

public long getItemId(int i) {

return i;

}

public View getView(int i, View view, ViewGroup viewGroup) {

View newView = null;

if(view != null) {

newView = view;

} else {

newView =(View)mInflater.inflate(R.layout.image_view, false);

}

Bitmap bitmap = BitmapFactory.decodeFile(mValues.get(i).fileName);

mBitmapRefs.add(new SoftReference(bitmap)); //此處加入ArrayList

((ImageView)newView).setImageBitmap(bitmap);

return newView;

}

}

2,解決Context引起的記憶體溢出:

在Android平台上,長期保持一些資源的引用,造成一些記憶體不能釋放,帶來的記憶體洩露問題很多。比如Context。

android中的很多資源檔案都需要一個Context引用來加載,如果這些資源沒有被釋放,那麼Context的引用不為null,造成對應的Activity即使 調用了finish()但其占有的記憶體依然不能被釋放。這是 因為在Java或者Android記憶體機制中,頂點的結點釋放前必須保證其他對象沒有調用才能被系統GC回收釋放。我們來看一段代碼:

SoundManager.getInstance(this).play(SoundManger.MAIN_BG_SOUND);

從這段代碼可以看出,聲音管理類是一個單例,它對于整個應用程序來說是全局的,在進入應用的時候建立這個單利直到應用結束,這個單例才會被釋放。大家可以看到這個類在得到單例的時候需要傳遞一個Context對象作為參數,因為要利用Context來加載聲音資源。這就導緻如果目前Activity調用了finish()全依然不能被GC,因為聲音管理類是全局的,它持有了目前Activity的應用,阻止了其被GC。 解決的辦法是盡量使用全局的Context來加載資源。修改如下:

SoundManager.getInstance(this.getApplicationContext).play(SoundManger.MAIN_BG_SOUND);

3,解決Thread 線程引起的記憶體溢出

如下代碼:

private class MyThread extends Thread{

@Override

public void run() {

super.run();

while(bFlag)

{

//do somthing

}

}

MyThread mThread = new MyThread();

mThread.start();

這端代碼 在主線程裡新開了一個線程,并且線上程裡循環處理一些邏輯。問題在于 如果控制線程結束的bFlag如果在Activity銷毀時沒有置為 false 将會産生很嚴重的後果。線程的一個特點是生命周期的不可控。如果Activity銷毀時,沒有結束線程的運作,那麼不僅阻止了Activity被GC,而且大大降低了程式的性能。假如,再重新進入這個Activity,那麼又建立了一個死循環的線程,而之前的那個線程依然在運作,這樣程式就會非常的卡。是以 一定要注意,銷毀Activity時一定要結束線程。

總而言之,想要避免context 相關的記憶體洩漏 ,記住以下幾點:

a.不要對activity 的context 長期引用( 一個activity 的引用的生存周期應該和activity 的生命周期相同)

b.試着使用關于application的 context 來替代和activity相關的context

c.如果一個acitivity 的非靜态内部類的生命周期不受控制,那麼避免使用它;使用一個靜态的内部類并且對其中的activity 使用一個弱引用。解決這個問題的方法是使用一個靜态的内部類,并且對它的外部類有一WeakReference,就像在ViewRoot中内部類W所做的就是這麼個例子。