美文网首页Android问题解决方案积累
Android 内存泄露处理小结

Android 内存泄露处理小结

作者: 我在Bug的尽头等你 | 来源:发表于2019-09-26 10:47 被阅读0次

    内存泄露的概念:强引用所指向的对象不会被回收,可能导致内存泄漏,虚拟机宁愿抛出OOM也不会去回收他指向的对象;意思就是你用资源的时候为他开辟了一段空间,当你用完时忘记释放资源了,这时内存还被占用着,一次没关系,但是内存泄漏次数多了就会导致内存溢出。

    以下是我在项目中遇到的三种内存泄露的情况,逐个分析给出解决方案。

    1. 单例的使用导致内存泄露:

    Android的单例模式在我们项目开发中经常会用到,不过使用的不恰当的话也会造成内存泄漏。因为单例的静态特性使得单例的生命周期和应用的生命周期一样长, 这就说明了如果一个对象已经不需要使用了,而单例对象还持有该对象的引用,那么这个对象将不能被正常回收,这就导致了内存泄漏。
    Android中习惯使用单例的常见类: xxxManager , xxxHelper , xxxUtils 等。


    方案1.png

    将传入的Context对象替换为context.getApplicationContext(),使我们单例的生命周期和应用的一样长,这样就防止了内存泄漏,这也是最好的解决方式。

    或者使用软引用,如果需要使用相应的context对象,只需要使用 wr.get()即可,代码如下:

    方案2.png

    2.使用webView导致的内存泄露

    我们在创建webView对象时,尽量上下文变量使用applicationContext:

    webView = new WebView(getApplicationContext()); 
    webView.getSettings().setJavaScriptEnabled(true);
    

    另外记住当activity生命周期结束时及时销毁/释放资源:

    @Override
        protected void onDestroy() {
            if (webView != null) {
                ViewParent parent = webView.getParent();
                if (parent != null) {
                    ((ViewGroup) parent).removeView(webView);
                }
                webView.stopLoading();
                webView.getSettings().setJavaScriptEnabled(false);
                webView.clearHistory();
                webView.removeAllViews();
                webView.destroy();
            }
            super.onDestroy();
        }
    

    3.使用handler导致的内存泄露:

    ①先说handler导致activity内存泄露的原因

    handler发送的消息在当前handler的消息队列中,如果此时activity finish掉了,那么消息队列的消息依旧会由handler进行处理,若此时handler声明为内部类(非静态内部类),我们知道内部类天然持有外部类的实例引用,这样在GC垃圾回收机制进行回收时发现这个Activity居然还有其他引用存在,因而就不会去回收这个Activity,进而导致activity泄露。

    ②为何handler要定义为static?

    因为静态内部类不持有外部类的引用,所以使用静态的handler不会导致activity的泄露

    ③为何handler要定义为static的同时,还要用WeakReference 包裹外部类的对象?

    这是因为我们需要使用外部类的成员,可以通过"activity. "获取变量方法等,如果直接使用强引用,显然会导致activity泄露。

    解决内存泄露:

    public class MainActivity extends AppCompatActivity {
    
        TextView mTextView;
    
        MyHandler mMyHandler;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mTextView = findViewById(R.id.tv_handler);
            mMyHandler = new MyHandler(MainActivity.this);
            doInBackground();
        }
    
        private static class MyHandler extends Handler {
            private WeakReference<MainActivity> mWeakReference;
    
            public MyHandler(MainActivity activity) {
                mWeakReference = new WeakReference<>(activity);
            }
    
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                MainActivity mainActivity = mWeakReference.get();
                switch (msg.what) {
                    case 1:
                        if (mainActivity != null) {
                            mainActivity.mTextView.setText(msg.obj + "");
                        }
                        break;
                    default:
                        break;
                }
            }
        }
    
        private void doInBackground() {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        //模拟耗时操作
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //耗时操作完成,发送消息给UI线程
                    Message msg = Message.obtain();
                    msg.what = 1;
                    msg.obj = "更新UI";
                    mMyHandler.sendMessage(msg);
                }
            }).start();
        }
    
    }
    

    需要特别注意Context的使用:

    Context的正确姿势:
    1:当Application的Context能搞定的情况下,并且生命周期长的对象,优先使用Application的Context。
    2:不要让生命周期长于Activity的对象持有到Activity的引用。
    3:尽量不要在Activity中使用非静态内部类,因为非静态内部类会隐式持有外部类实例的引用,如果使用静态内部类,将外部实例引用作为弱引用持有。

    相关文章

      网友评论

        本文标题:Android 内存泄露处理小结

        本文链接:https://www.haomeiwen.com/subject/rvcbuctx.html