Android 中容易触发内存泄漏的点,与相应的解决方式

Android 内存泄漏的几种可能:
一般内存泄漏的原因是:由忘记释放分配的内存导致的(cursor、stream等)
逻辑内存泄漏的原因是:当应用不再需要这个对象,仍未释放该对象的所有引用。

(1)static  Activity:
在类中定义了静态Activity变量,把当前运行的Activity实例赋值于这个静态变量,如果这个静态变量在Activity生命周期结束后
没有清空,就会导致内存泄漏。因为static变量时贯穿这个应用的生命周期的,导致这个Activity会一直存在应用进程中。
    static Activity activity;
    
    void setStaticActivity() {
      activity = this;
    }
    
    View saButton = findViewById(R.id.sa_button);
    saButton.setOnClickListener(new View.OnClickListener() {
      @Override public void onClick(View v) {
        setStaticActivity();
        nextActivity();
      }
    });

解决办法:
使用弱引用代替强引用
 private static WeakReference<MainActivity> activityReference;

    void setStaticActivity() {
        activityReference = new WeakReference<MainActivity>(this);
    }

(2)static View:
如果一个View的初始化耗费大量资源,而且一个Activity生命周期保持不变,那么可以把它变成static,加载到视图树上。当
Activity销毁事,应当释放资源。(这个static view应当置null)
    static view;
    
    void setStaticView() {
      view = findViewById(R.id.sv_button);
    }
    
    View svButton = findViewById(R.id.sv_button);
    svButton.setOnClickListener(new View.OnClickListener() {
      @Override public void onClick(View v) {
        setStaticView();
        nextActivity();
      }
    });
解决办法:使用弱引用或者置空的方式来清除引用
private static View view;

@Override
public void onDestroy() {
    super.onDestroy();
    if (view != null) {
        unsetStaticView();
    }
}

void unsetStaticView() {
    view = null;
}

(3)Inner class
假设Activity中有个内部类,这样做可以提高可读性和封装性,但是假如我们创建一个内部类,而且持有一个静态变量的引用,那么
内存泄漏就离你不远了(需要销毁的时候置空)内部类的优势之一就是可以访问外部类,但不幸的是,导致内存泄漏的原因就是nei
部类持有外部类实例的强引用。
       private static Object inner;
       
       void createInnerClass() {
        class InnerClass {
        }
        inner = new InnerClass();
    }
    
    View icButton = findViewById(R.id.ic_button);
    icButton.setOnClickListener(new View.OnClickListener() {
        @Override public void onClick(View v) {
            createInnerClass();
            nextActivity();
        }
    });
解决办法:
避免静态变量
private Object inner;

void createInnerClass() {
    class InnerClass {
    }
    inner = new InnerClass();
}

(4)匿名内部类,当再activity中定义了匿名的AsyncTask。当异步任务在后台执行耗时任务期间,Activity被销毁,这个被
AsyncTask持有的Activity实例就不会内垃圾回收器回收,知道异步任务结束。
    void startAsyncTask() {
        new AsyncTask<Void, Void, Void>() {
            @Override protected Void doInBackground(Void... params) {
                while(true);
            }
        }.execute();
    }
    
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    View aicButton = findViewById(R.id.at_button);
    aicButton.setOnClickListener(new View.OnClickListener() {
        @Override public void onClick(View v) {
            startAsyncTask();
            nextActivity();
        }
    });
解决办法:
不能通过移除静态成员变量解决,因为线程是与生命周期相关的,为了避免泄漏,必须舍弃匿名的写法,把子类生命为静态内部类。
静态内部类不持有外部类的引用,打破了链式引用。
private static class NimbleTask extends AsyncTask<Void, Void, Void> {
    @Override protected Void doInBackground(Void... params) {
        while(true);
    }
}

void startAsyncTask() {
    new NimbleTask().execute();
}

(5)handler
定义匿名的Runnable,用匿名类Handler执行,Runnable内部类会持有外部类的隐式引用,被传递到Handler的消息对象MessageQueue中,在Message
消息还没有被吃力之前,Activity实例不会被销毁,导致内存泄漏。
    void createHandler() {
        new Handler() {
            @Override public void handleMessage(Message message) {
                super.handleMessage(message);
            }
        }.postDelayed(new Runnable() {
            @Override public void run() {
                while(true);
            }
        }, Long.MAX_VALUE >> 1);
    }
    
    
    View hButton = findViewById(R.id.h_button);
    hButton.setOnClickListener(new View.OnClickListener() {
        @Override public void onClick(View v) {
            createHandler();
            nextActivity();
        }
    });
解决办法:
private static class NimbleHandler extends Handler {
    @Override public void handleMessage(Message message) {
        super.handleMessage(message);
    }
}

private static class NimbleRunnable implements Runnable {
    @Override public void run() {
        while(true);
    }
}

void createHandler() {
    new NimbleHandler().postDelayed(new NimbleRunnable(), Long.MAX_VALUE >> 1);
}

(6)Thread和TimerTask的不合理使用导致内存泄漏。只要是匿名类的实例,不管是不是在工作线程,都会持有Activity的引用,导致内存泄漏。
    void spawnThread() {
        new Thread() {
            @Override public void run() {
                while(true);
            }
        }.start();
    }
    
    View tButton = findViewById(R.id.t_button);
    tButton.setOnClickListener(new View.OnClickListener() {
      @Override public void onClick(View v) {
          spawnThread();
          nextActivity();
      }
    });

    void scheduleTimer() {
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                while(true);
            }
        }, Long.MAX_VALUE >> 1);
    }
    
    View ttButton = findViewById(R.id.tt_button);
    ttButton.setOnClickListener(new View.OnClickListener() {
        @Override public void onClick(View v) {
            scheduleTimer();
            nextActivity();
        }
    });

解决办法:
private static class NimbleTimerTask extends TimerTask {
    @Override public void run() {
        while(true);
    }
}

void scheduleTimer() {
    new Timer().schedule(new NimbleTimerTask(), Long.MAX_VALUE >> 1);
}


(7)Context.getSystemService(int name)可以获取系统服务,
这些服务工作在各自的进程中,帮助应用处理后台任务,硬件交互。使用这些服务的时候,可以注册监听器,这会导致服务持有了
Context的引用,如果Activity销毁的时候没有注销这些监听器,会导致内存泄漏。
        void registerListener() {
               SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
               Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ALL);
               sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_FASTEST);
        }
        
        View smButton = findViewById(R.id.sm_button);
        smButton.setOnClickListener(new View.OnClickListener() {
            @Override public void onClick(View v) {
                registerListener();
                nextActivity();
            }
        });
解决办法:在Activity结束时注销监听器
private SensorManager sensorManager;
private Sensor sensor;

@Override
public void onDestroy() {
    super.onDestroy();
    if (sensor != null) {
        unregisterListener();
    }
}

void unregisterListener() {
    sensorManager.unregisterListener(this, sensor);
}
 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值