Android 記憶體管理記錄
專案中用到大量大圖,造成快速切換Activity後記憶體不足,如登入介面用到3M高清大圖,裝置選擇用到5張大圖背景疊加效果,主介面用到了5張遮罩大圖,設定介面總的子activity中也有大圖出現。
啟動Splash——裝置選擇介面(保留棧低,不finish,但會把背景圖片回收)-->主介面--->設定介面-->設定子介面(有大圖背景\或者WebView(WebView記憶體洩漏 https://www.jianshu.com/p/3e8f7dbb0dc7)
通過跟蹤除錯發現,在快速返回過程中,activity沒有及時呼叫ondestry,這就會出現圖片記憶體沒有得到釋放,而此時已經返回到了裝置選擇介面,開啟載入裝置選擇介面的大圖背景。問題發現了百度了ImageView 釋放的記憶體的關鍵字,發現前篇一律的方式都是bitmap的回收方法,但在實際中被並沒有達到效果。
最後通過檢視android 記憶體管理機制,以及andorid 弱引用和軟引用得到了啟發。
當我們直接在xml中ImageView設定了背景圖片和src時候,view中(長期持有 Context 的引用()個人理解),這樣就會出現activity解釋被finish掉了,但它所佔用的記憶體沒有得到釋放,這樣imageview中的 bitmap記憶體依然佔用著。
軟引用 和 弱引用 (引用自https://www.cnblogs.com/zhaoyanjun/p/5977190.html)
1. SoftReference<T>:軟引用-->當虛擬機器記憶體不足時,將會回收它指向的物件;需要獲取物件時,可以呼叫get方法。
2. WeakReference<T>:弱引用-->隨時可能會被垃圾回收器回收,不一定要等到虛擬機器記憶體不足時才強制回收。要獲取物件時,同樣可以呼叫get方法。
3. WeakReference一般用來防止記憶體洩漏,要保證記憶體被虛擬機器回收,SoftReference多用作來實現快取機制(cache);
最後參考ImageLoader 寫了一個demo
package com.example.zdyl;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.util.Log;
public class MemoryCache {
//Bitmap 用WeakReference<T>:弱引用-->在系統gc 過程中隨時可能會被垃圾回收器回收
private static final String TAG = "MemoryCache";
//bitmap 管理集合
private Map<String, WeakReference<Bitmap>> cache = new LinkedHashMap<String, WeakReference<Bitmap>>();// private Map<String, Bitmap> cache=Collections.synchronizedMap(
// new LinkedHashMap<String, Bitmap>(10,1.5f,true));//Last argument true for LRU ordering
private long size=0;//current allocated size
private long limit=1000000;//max memory in bytes
public MemoryCache(){
//use 25% of available heap size
setLimit(Runtime.getRuntime().maxMemory()/4);
}
public void setLimit(long new_limit){
limit=new_limit;
Log.i(TAG, "MemoryCache will use up to "+limit/1024./1024.+"MB");
}
//將bitmap丟入集合
public void put(String id, WeakReference<Bitmap> bitmap){
try{
cache.put(id, bitmap);
}catch(Throwable th){
th.printStackTrace();
}
}
public void clear() {
try{
//NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78
Iterator<Entry<String, WeakReference<Bitmap>>> iter= cache.entrySet().iterator();//least recently accessed item will be the first one iterated
while(iter.hasNext()){
Entry<String, WeakReference<Bitmap>> entry = iter.next();
WeakReference<Bitmap> tmp = entry.getValue();
if(tmp!=null ){
Bitmap bitmap = tmp.get();
if(bitmap!=null && !bitmap.isRecycled()){
bitmap.recycle();
}
tmp = null;
bitmap =null;
}
}
cache.clear();
size=0;
}catch(NullPointerException ex){
ex.printStackTrace();
}
}
long getSizeInBytes(Bitmap bitmap) {
if(bitmap==null)
return 0;
return bitmap.getRowBytes() * bitmap.getHeight();
}
//移除,釋放指定bitmap
public void removeCache(int id) {
WeakReference<Bitmap> tmp = cache.get(""+id);
//系統gc可能已經將bitmap 記憶體釋放了,需要判斷null
if(tmp!=null ){
Bitmap bitmap = tmp.get();if(bitmap!=null && !bitmap.isRecycled()){
bitmap.recycle();
}
cache.remove(tmp);
tmp = null;
bitmap =null;
}
}
}
package com.example.zdyl; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; import java.net.HttpURLConnection; import java.net.URL; import java.util.Collections; import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import android.os.Handler; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.view.View; import android.widget.ImageView;
//讀取res中的bitmap 設定到wiew中 public class ImageLoader {
static MemoryCache memoryCache=new MemoryCache();
public static boolean isFirst;
public ImageLoader(Context context){
}
public static void decode(Resources context,int id,View view){
Bitmap bmp=BitmapFactory.decodeResource(context, id);
if(view instanceof ImageView){
((ImageView) view).setImageBitmap(bmp);
}else{
view.setBackground(new BitmapDrawable(bmp));
}
// 軟引用的Bitmap物件,這樣系統會在gc過程中回收掉bitmap,直接使用強引用物件的話,即使呼叫了bitmap的回收函式 //但是imageview 中bitmap在gc的時候跟隨了activity的記憶體,如果activity因為context物件的長期被引用,那麼bitmap的記憶體就得不到銷燬WeakReference<Bitmap> softBitmap = new WeakReference<Bitmap>(bmp);
// 新增該物件到Map中使其快取
memoryCache.put(""+view.getId(),softBitmap );
bmp = null;
}
public static void removeCache(int id){
memoryCache.removeCache(id);
}
public static void clearCache() {
memoryCache.clear();
}
}
package com.example.zdyl;
import java.util.ArrayList;
import java.util.List;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
public class MainActivity extends Activity {
private RelativeLayout t;
private ImageView t1;
private ImageView t2;
private ImageView t3;
private ImageView t4;
private ImageView t5,t6,t7,t8,t9;
private MemoryCache mMemoryCache=new MemoryCache();
private List<View> views = new ArrayList<View>();
//由於圖片用的是公司專案中的圖片,這裡就不提供了,見諒,可以找幀動畫中圖片資源來代替。
private int[] icons ={iconframe_001,iconframe_002,
iconframe_005,iconframe_006,
iconframe_007,iconframe_008,
iconframe_009,iconframe_010};
private ImageLoader loader;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
t = (RelativeLayout)findViewById(R.id.t0);
t1 = (ImageView)findViewById(R.id.t1);
t2 = (ImageView)findViewById(R.id.t2);
t3 = (ImageView)findViewById(R.id.t3);
t4 = (ImageView)findViewById(R.id.t4);
t5 = (ImageView)findViewById(R.id.t5);
t6 = (ImageView)findViewById(R.id.t6);
t7 = (ImageView)findViewById(R.id.t7);
t8 = (ImageView)findViewById(R.id.t8);
t9 = (ImageView)findViewById(R.id.t9);
views.add(t);
views.add(t1);
views.add(t2);
views.add(t3);
views.add(t4);
views.add(t5);
views.add(t6);
views.add(t7);
views.add(t8);
views.add(t9);
loader = new ImageLoader(this);
//因為要管理bitmap物件,所以沒有使用xml中直接設定背景和src
for(int i=0;i<views.size();i++){
loader.decode(this.getResources(), icons[i], views.get(i));}
}
public void d(){
//loader.clearCache();
for (int i = 0; i < views.size(); i++) {
View view = views.get(i);
if (view instanceof ImageView) {
((ImageView) view).setImageBitmap(null);
} else {
view.setBackground(null);
}
ImageLoader.removeCache(view.getId());
}
views.clear();
}
public void onClear(View v){
}
public void onClearc(View v) {
if(this.isFinishing()){
return;
}
Intent i = new Intent(MainActivity.this,MainActivity2.class);
startActivity(i);
if(!ImageLoader.isFirst){
ImageLoader.isFirst = true;
return;
}
finish();
}
@Override
public void finish() {
super.finish();
d();
}
}
demo傳輸門(只包含as專案src 部分,):https://download.csdn.net/download/zdy10326621/10496926