Android 内存管理记录

项目中用到大量大图,造成快速切换Activity后内存不足,如登录界面用到3M高清大图,设备选择用到5张大图背景叠加效果,主界面用到了5张遮罩大图,设置界面总的子activity中也有大图出现。

启动Splash——设备选择界面(保留栈低,不finish,但会把背景图片回收)-->主界面--->设置界面-->设置子界面(有大图背景\或者WebView(WebView内存泄漏 https://www.jianshu.com/p/3e8f7dbb0dc7)

在设置子界面快速返回到设备选择界面过程中会出现在主界面,停顿过长然后内存爆增加导致UI异常。

通过跟踪调试发现,在快速返回过程中,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 过程中随时可能会被垃圾回收器回收

扫描二维码关注公众号,回复: 3911636 查看本文章

    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_003,iconframe_004,
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

猜你喜欢

转载自blog.csdn.net/zdy10326621/article/details/80795756