Android 性能优化之——内存优化

内存溢出(OOM)

应用所需要的内存超过这个系统分配的内存限额,这就造成了内存溢出而导致应用Crash

内存泄漏

当一个对象已经不需要再使用了,本该被回收时,而另外一个正在使用的对象持有它的引用从而导致它不能被回收,这就导致本该被回收的对象不能被回收而停留在堆内存中,导致内存泄漏

关系:

内存泄漏是造成内存溢出的主要原因之一,因此在开发中应避免内存泄漏。

常见几种造成内存泄漏的案例:

一、单例造成的内存泄漏

单例的静态特性使得单例的生命周期和应用的生命周期一样长,这就说明了如果一个对象已经不需要使用了,而单例对象还持有该对象的引用,那么这个对象将不能被正常回收,这就导致了内存泄漏。

/**
 * 1、传入的是Application的Context:这将没有任何问题,因为单例的生命周期和Application的一样长 ;
 * 2、传入的是Activity的Context:当这个Context所对应的Activity退出时,由于该Context和Activity
 * 的生命周期一样长(Activity间接继承于Context),所以当前Activity退出时它的内存并不会被回收,
 * 因为单例对象持有该Activity的引用,从而造成内存泄漏。
 */
public class AppManager {

    private static AppManager instance;
    private Context mContext;

    private AppManager(Context context){
        mContext = context;
    }

    public static AppManager getInstance(Context context) {
        if (instance == null) {
            synchronized (instance){
                if(instance!=null){
                    instance = new AppManager(context);
                }
            }
        }
        return instance;
    }
}
二、非静态内部类创建静态实例造成的内存泄漏

非静态的内部类会持有外部类的一个隐式引用

/**
 * 非静态内部类持有外部类的隐式引用
 * 而用该非静态内部类创建  静态的实例
 * 该实例的生命周期和应用的一样长,这就导致了该静态实例一直会持有该Activity的引用
 */
public class WorkActivity extends JYActivity{
    private static PersonBean person = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if(person!=null){
            person = new PersonBean();
        }
        //...
    }


    class PersonBean{
        //...
    }
}
三、Handler造成的内存泄漏

Handler的使用编码不规范即有可能造成内存泄漏

/**
 * 非静态内部类持有外部类的隐式引用
 * 由于mHandler是Handler的非静态匿名内部类的实例,所以它持有外部类Activity的引用
 * 消息队列是在一个Looper线程中不断轮询处理消息,那么当这个Activity退出时,
 * 消息队列中还有未处理的消息或者正在处理消息,而消息队列中的Message持有mHandler实例的引用
 * mHandler又持有Activity的引用,所以导致该Activity的内存资源无法及时回收,引发内存泄漏
 */
public class WorkActivity extends JYActivity{
    private TextView tvShow;

    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            tvShow.setText(msg.arg1+"测试");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvShow = (TextView) this.findViewById(R.id.tv_item);
        loadData();
    }

    private void loadData() {
        Message msg = mHandler.obtainMessage();
        mHandler.sendMessage(msg);
    }

}

正确写法

/**
 * 非静态内部类持有外部类的隐式引用
 * 创建静态的内部类,弱引用Activity,从而可以持有Activity实例来做更新UI操作
 * 在onDestroy方法中移除消息队列中的消息,从而更好的避免了内存泄漏
 *
 */
public class WorkActivity extends JYActivity{
    private TextView tvShow;

    private MyHandler mHandler = new MyHandler(this);

    public static class MyHandler extends Handler{
        private WeakReference<Context> wrf;

        public MyHandler(Context context){
            wrf = new WeakReference<Context>(context);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            WorkActivity temp = (WorkActivity) wrf.get();
            if(temp!=null){
                temp.tvShow.setText(msg+"msg");
            }

        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvShow = (TextView) this.findViewById(R.id.tv_item);
        loadData();
    }

    private void loadData() {
        Message msg = mHandler.obtainMessage();
        mHandler.sendMessage(msg);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandler.removeCallbacksAndMessages(null);
    }
}
四、线程造成的内存泄漏
/**
 * 非静态内部类持有外部类的隐式引用
 * 子线程内部类持有Activity的引用,当活动关闭时,子线程任务还没有执行完毕
 * 导致Activity的内存资源无法回收,造成内存泄漏
 */
public class WorkActivity extends JYActivity{
    private TextView tvShow;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvShow = (TextView) this.findViewById(R.id.tv_item);

        new Thread(new Runnable() {
            @Override
            public void run() {
                //...耗时操作
            }
        }).start();
    }

}
/**
 * 非静态内部类持有外部类的隐式引用
 * 子线程内部类持有Activity的引用,当活动关闭时,子线程任务还没有执行完毕
 * 导致Activity的内存资源无法回收,造成内存泄漏
 */
public class WorkActivity extends JYActivity{
    private TextView tvShow;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvShow = (TextView) this.findViewById(R.id.tv_item);

        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... params) {
                //...耗时操作
                return null;
            }
        }.execute();
    }

}
如何避免
/**
 * 非静态内部类持有外部类的隐式引用
 * 定义静态内部类,避免内存泄漏 
 */
public class WorkActivity extends JYActivity{
    private TextView tvShow;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvShow = (TextView) this.findViewById(R.id.tv_item);
        new Thread(new MyRunnable()).start();
    }

    static class MyRunnable implements Runnable{
        @Override
        public void run() {
            //...耗时操作
        }
    }
}
/**
 * 非静态内部类持有外部类的隐式引用
 * 定义静态内部类,+ 若引用  避免内存泄漏
 */
public class WorkActivity extends JYActivity{
    private TextView tvShow;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvShow = (TextView) this.findViewById(R.id.tv_item);
        new MyAsyncTask(this).execute();
    }

    static class MyAsyncTask extends AsyncTask<Void, Void, Void> {
        private WeakReference<Context> weakReference;

        public MyAsyncTask(Context context) {
            weakReference = new WeakReference<>(context);
        }

        @Override
        protected Void doInBackground(Void... params) {
            //...  耗时操作
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            MainActivity activity = (MainActivity) weakReference.get();
            if (activity != null) {
                //...
            }
        }
    }
}
五、资源未关闭造成的内存泄漏

对于使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,造成内存泄漏。

六、属性动画为及时停在

属性动画未在onDestory中停止,造成动画一直播放下去(即使在界面上看不到动画效果),活动的view被动画持有,view持有Activity的引用,最终导致Activity无法释放,造成内存泄漏

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值