美文网首页
解决我对静态类/弱引用的理解的一些博客与内存泄露总结

解决我对静态类/弱引用的理解的一些博客与内存泄露总结

作者: 一个冬季 | 来源:发表于2019-03-12 09:28 被阅读0次

    Java静态内部类的实例化问题
    单例模式 - 只有一个实例
    静态内部类什么时候被释放?会一直存在么?
    关于弱引用WeakReference的一点疑问
    静态方法与非静态方法的区别
    静态内部类的生命周期
    程序设计之单例模式VS静态方法
    java静态方法和非静态方法的区别
    弱引用——WeakReference——所引用的对象的回收规则

    大量静态方法占很多内存么?

    1、不管是静态方法,非静态方法都是占内存的
    2、现在举个例子,A类含有100个静态方法,B类含有100非静态方法,当创建类/A.方法,所耗的内存都一样,唯一区别是,我B类长期不用就会被gc回收,A类里的方法就不同了,它会一直存在内存中
    3、什么时候用静态方法,什么时候用单例呢?
    如果你你一个方法利用率可以达到50%以上,你就可以考虑用静态方法,其它时候就用单例类

    对 WeakReference 研究

    对于弱引用我们经常看到类似如下这样的代码

     private TestNeiCunXieLouActivity mActivity;//某个activity
     public WeakReference<TestNeiCunXieLouActivity> weakReference;
        public TestRunner(TestNeiCunXieLouActivity activity) {
            weakReference = new WeakReference<TestNeiCunXieLouActivity>(activity);
            this.mActivity = weakReference.get();
        }
    

    然后就说这样就可以解决内存泄漏的问题,当然了可能TestRunner 前面可能会加一个static。今天研究的是,我们不加static,只使用弱引用也可以解决内存泄漏的问题么??为了简单起见,代码能省就省

    public class TestNeiCunXieLouActivity extends BaseActivity implements View.OnClickListener{
        private TestRunner testRunner;//一个线程类
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            init();
            setTitleHeader("测试内存泄漏");
        }
    
        @Override
        protected int getLayoutId() {
            return R.layout.activity_test_neicunxielou;
        }
    
        @OnClick({R.id.bt_test_neicunxielou_neicunxielou})
        @Override
        public void onClick(View v) {
            switch (v.getId()){
                case R.id.bt_test_neicunxielou_neicunxielou:{
                    if (testRunner == null){
                        testRunner = new TestRunner(this);
                        new Thread(testRunner).start();
                    }else {
                        testRunner.weakReference.clear();//清除引用
                        testRunner.weakReference.get();
                        testRunner.weakReference=null;
                    }
                }
                break;
            }
        }
    }
    

    这里很简单TestRunner 是一个实现了Runnable的类

    public class TestRunner implements Runnable{
        private String TAG = TestRunner.class.getSimpleName();
        private TestNeiCunXieLouActivity mActivity;
        public WeakReference<TestNeiCunXieLouActivity> weakReference;
        public TestRunner(TestNeiCunXieLouActivity activity) {
            weakReference = new WeakReference<TestNeiCunXieLouActivity>(activity);
            this.mActivity = weakReference.get();
        }
    
        @Override
        public void run() {
            while (true){
                try {
                    Thread.sleep(1000);
                    if (mActivity == null){
                        Log.i(TAG,"mActivity,是null 了");
                    }else {
                        Log.i(TAG,"mActivity,我还没有变空哦,哈哈哈哈");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    当我们第一次直接点击按钮的时候,1秒过后就会打印, “mActivity,我还没有变空哦,哈哈哈哈”,过一会,我们直接第二次点击按钮,将弱引用清空,发现打印的日志, “mActivity,我还没有变空哦,哈哈哈哈”


    点击第一次,点击第二次.png

    此时我们点击返回按钮,不关闭线程,发现打印的日志, “mActivity,我还没有变空哦,哈哈哈哈”

    总结:

    第一次我们点击按钮这样获取Activity

     private TestNeiCunXieLouActivity mActivity;//某个activity
     public WeakReference<TestNeiCunXieLouActivity> weakReference;
        public TestRunner(TestNeiCunXieLouActivity activity) {
            weakReference = new WeakReference<TestNeiCunXieLouActivity>(activity);
            this.mActivity = weakReference.get();//获取到activity
        }
    

    然后第二次点击按钮,清除弱应用

     testRunner.weakReference.clear();
     testRunner.weakReference.get();
    

    最后发现还是能获取到Activity的引用,上面给的日志已经充分的证明了,说明,我们想清除持有Activity失败

    解决办法

    1、我们需要在activity类,重新复写onDestroy()

     @Override
        protected void onDestroy() {
            super.onDestroy();
            testRunner.onDestory();
        }
    

    在线程类要自己写onDestory()方法

      public void onDestory(){
            weakReference.clear();
            this.mActivity = weakReference.get();
        }
    

    此时获取到的weakReference.get() == null


    没有引用了.png

    这样就不会获取到activity的引用了,当然线程我还是没关闭的,这个不在我们讨论范围内

    所以当我们通过这样获取到Actity引用的时候

     this.mActivity = weakReference.get();
    

    需要通过这样的方法去除引用

       weakReference.clear();
       this.mActivity = weakReference.get();
    

    2、直接操作weakReference.get()即可,不将其赋值给强引用的Activity

    接口出现内存泄露解决办法

    经过上面的测试,当我们通过弱引用获取到了Activity,并又强制赋值给当前类的全局Activity的时候,我们仍旧能持有activity。在这里接口的解决办法同上面的2种一样,我就只列举最简单的方式

      public WeakReference<ReadMsgListener> weakReference;
       public interface ReadMsgListener{
            void onGetMessageFromService(String value);
        }
    
        public void setUnReadMsgListener(ReadMsgListener xunReadMsgListener){
            weakReference = new WeakReference<ReadMsgListener>(xunReadMsgListener);
        }
    
        //接口回调
         if (weakReference.get() != null){
               weakReference.get().onGetMessageFromService("我是接口,我不是空的");
        }
    

    相关文章

      网友评论

          本文标题:解决我对静态类/弱引用的理解的一些博客与内存泄露总结

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