当前位置:   article > 正文

【安卓】常见的安卓中的内存泄漏总结_collectorsystem.getinstance(mcontext).stop();

collectorsystem.getinstance(mcontext).stop();

常见的安卓中的内存泄漏总结


  系统 内存泄漏也称作“存储渗漏”,用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束。(其实说白了就是该内存空间使用完毕之后未回收)即所谓内存泄漏。
 系统内存泄漏形象的比喻是“操作系统可提供给所有进程的存储空间正在被某个进程榨干”,最终结果是程序运行时间越长,占用存储空间越来越多,最终用尽全部存储空间,整个系统崩溃。所以“内存泄漏”是从操作系统的角度来看的。这里的存储空间并不是指物理内存,而是指虚拟内存大小,这个虚拟内存大小取决于磁盘交换区设定的大小。由程序申请的一块内存,如果没有任何一个指针指向它,那么这块内存就泄漏了。

     Android的内存泄露(Memory Leak):

进程中某些对象已经没有使用价值了,但是他们却还可以直接或者间接地被引用到GC Root导致无法回收。
当内存泄露过多的时候,再加上应用本身占用的内存,日积月累最终就会导致内存溢出OOM.
内存溢出(OOM):
当应用占用的heap资源超过了Dalvik虚拟机分配的内存就会内存溢出。比如:加载大图片等。


1.静态变量引起的内存泄露

当调用getInstance时,如果传入的context是Activity的context。只要这个单利没有被释放,那么这个Activity也不会被释放一直到进程退出才会释放。
public class MyUtil {
   private static MyUtil instance;
   private Context context;
   private MyUtil(Context context){
this.context = context;
   }

   public static MyUtil getInstance(Context mContext){
if(instance == null){
   instance = new MyUtil(mContext);
}
return instance;
   }

2.非静态内部类引起内存泄露

(包括匿名内部类)
错误的示范:

 public void loadData(){

 //隐式持有MainActivity实例。MainActivity.this.a

new Thread(new Runnable() {
   @Override
   public void run() {
 while(true){
   try {
//int b=a;
Thread.sleep(1000);
   } catch (InterruptedException e) {
     e.printStackTrace();
   }}}}).start();
   }
解决方案:
将非静态内部类修改为静态内部类。(静态内部类不会隐式持有外部类)


当使用软引用或者弱引用的时候,MainActivity难道很容易或者可以被GC回收吗?
GC回收的机制是什么?当MainActivity不被任何的对象引用。
虽然Handler里面用的是软引用/弱引用,但是并不意味着不存在其他的对象引用该MainActivity。

我连MainActivity都被回收了,那Handler就有问题了。

        {
            mHandler.sendEmptyMessage(0);
            mHandler.sendMessageAtTime(msg,10000);//atTime

        }
         //activity onDestroy把timer.cancel掉然后赋空
        //错误的示范:
//    mHandler是匿名内部类的实例,会引用外部对象MainActivity.this。如果Handler在Activity退出的时候,
           它可能还活着,这时候就会一直持有Activity。
        private Handler mHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what){
                    case 0:
                        //加载数据
                        break;
                }
            }
        };

        //解决方案:
 private static class MyHandler extends Handler{
     private MainActivity mainActivity;//直接持有了一个外部类的强引用,会内存泄露
           //设置软引用保存,当内存一发生GC的时候就会回收。
    private WeakReference<MainActivity> mainActivity;
    public MyHandler(MainActivity mainActivity) {
        this.mainActivity = new WeakReference<MainActivity>(mainActivity);
    }
    @Override
    public void handleMessage (Message msg){
        super.handleMessage(msg);
        MainActivity main = mainActivity.get();
        if (main == null || main.isFinishing()) {
            return;
        }
        switch (msg.what) {
            case 0:
                //加载数据               
                MainActivity.this.a;
                int b = main.a;
                break;
        }
    }
};

3.不需要用的监听未移除会发生内存泄露

 譬如:
//        tv.setOnClickListener();//监听执行完回收对象
        //add监听,放到集合里面
        tv.getViewTreeObserver().addOnWindowFocusChangeListener(new ViewTreeObserver.OnWindowFocusChangeListener() {
            @Override
            public void onWindowFocusChanged(boolean b) {
                //监听view的加载,view加载出来的时候,计算他的宽高等。

                //计算完要移除这个监听
                tv.getViewTreeObserver().removeOnWindowFocusChangeListener(this);
            }
        });
   譬如:

   SensorManager sensorManager = getSystemService(SENSOR_SERVICE);

        Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ALL);
        sensorManager.registerListener(this,sensor,SensorManager.SENSOR_DELAY_FASTEST);
        //不需要用的时候记得移除监听
        sensorManager.unregisterListener(listener);

   

   譬如:

   自定义布局中的监听器:

public class MyView extends View{
    public  MyView(Context context){
        super(context);
        init();
    }
//错误写法
//    public MyView(Context context, AttributeSet attrs, MyListener myListener) {
//        super(context, attrs);
//        this.myListener = myListener;
//    }
    public interface MyListener{
        void myListenerCallback();
    }
    private void init(){
        ListenerCollector collector = new ListenerCollector();
        collector.setsListener(this,myListener);
    }
    private MyListener myListener = new MyListener() {
        @Override
        public void myListenerCallback() {
            System.out.print("有被调用");
        }
    };
}


public class ListenerCollector {
    /**
     * WeakHashMap,此种Map的特点是,当除了自身有对key的引用外,此key没有其他引用那么此map会自动丢弃此值
     * 例如:int a = 1;
     * Map weakmap = new WeakHashMap();
     * weakmap.put(a, "aaa");
     * a = null
     * //此时weakmap里面的a会被丢弃。
     */
    static private WeakHashMap<View, MyView.MyListener> sListener = new WeakHashMap<>();

    public void setsListener(View view, MyView.MyListener listener) {
        sListener.put(view, listener);
    }
    public static void clearListeners() {
        //移除所有监听。
        sListener.clear();
    }

}

调用 
    @Override
    protected void onStop() {
        super.onStop();
        ListenerCollector.clearListeners();
    }

4.无限循环动画
没有在onDestroy中停止动画,否则Activity就会变成泄露对象。

没有在onDestroy中停止动画,否则Activity就会变成泄露对象。

比如:轮播图效果等。


5.资源未关闭引起的内存泄露情况

比如:BroadCastReceiver、Cursor、Bitmap、IO流、自定义属性attribute
attr.recycle()回收。

当不需要使用的时候,要记得及时释放资源。否则就会内存泄露。


相关参考博文:

  http://www.cnblogs.com/shaweng/archive/2012/06/29/2570413.html

  http://blog.csdn.net/soiol/article/details/52486871

  http://blog.csdn.net/cyq1028/article/details/19980369

 
  http://www.2cto.com/kf/201111/109812.html

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
  

闽ICP备14008679号