Android-内存泄漏巧妙解决

来源:互联网 发布:积分系统数据库设计 编辑:程序博客网 时间:2024/05/19 04:54

内存泄漏

内存泄漏,当资源对象长期(例如Context)被引用,垃圾回收器就无法回收它,当然该对象占用的内存就无法被使用,这就造成内存泄露。

内存溢出,当对象的内存占用已经超出分配内存的空间大小,这时未经处理的异常就会抛出。

随着现在手机内存硬件环境越来越好,内存溢出的情况已经越来越少,而我们经常要面对的优化问题就是内存泄漏,造成内存泄漏,往往是我们不良的代码习惯,大量的内存泄漏问题会造成应用过度消耗内存,应用耗电等问题。

内存泄漏如何解决

内存泄漏如何解决,网上已经有很多优秀的博文进行解读。

例如 http://blog.csdn.net/u010687392/article/details/49909477

内存泄漏解决技巧

在日常开发中,我们遇到更多内存泄漏的问题,最常见的内存泄漏问题就是,我们经常接入一些SDK,一般情况很多SDK都会需要外部传入一个Listener的实例,这时候就会出现内存泄漏的隐患:

public class MainActivity extends Activity implements TestController.TestListener {         @Override                                                                               protected void onCreate(Bundle savedInstanceState) {                                        super.onCreate(savedInstanceState);                                                     setContentView(R.layout.activity_main);                                                 TestController.getsInstance().setListener(this);                                        TestController.getsInstance().run();                                                }                                                                                       @Override                                                                               public void onTest() {                                                                  }                                                                                   }                                                                                       
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

我们看到,MainActivity实现了TestController.TestListener接口,这时候相当于TestController持有了MainActivity的引用,如果此时我们按下返回键,回到手机桌面,这时候就出现了应用内存泄漏。借助leakcanary库我们可以看到:

原因分析:

由于TestController内部开启了线程,同时持有着MainActivity的引用,导致MainActivity实例对象无法被释放。

解决思路:

如何解决这种类型的内存泄漏,通常的思路是通过弱引用。当一个对象只有被弱引用指向的时候,那么它就随时会垃圾回收系统回收。

1)TestController内部解决

通常一个SDK内部出现了内存泄漏,我们第一个的想法就是让SDK内部增加解决的方法:

手动释放引用
public class TestController {    ...    public void setListener(TestListener testListener) {        this.mTestListener = testListener;    }    public void release() {        this.mTestListener = null;    }    ...}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
将对象引用改为弱引用
public class TestController {    ...    private WeakReference<TestListener> mTestListenerWeakReference;    public void setTestListener(TestListener testListener) {        this.mTestListenerWeakReference = new WeakReference<TestListener>(testListener);        }    ...}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

2)TestController外部解决

然而,有时候,我们不能总期待着别人帮我们去解决这个问题,由于时间紧急,我们可能自己去解决这个内存泄漏的问题。最理想的情况是,TestController持有的是一个弱引用,然而我们无法改动TestController内存的代码,这时候,我们还是有思路,可以使得TestController最后还是持有着一个弱引用的。

我们需要一个辅助的Listener,它需要实现TestListener接口,然后,在这个辅助的Listener内部持有TestListener的弱引用

/** * Created by linzewu on 17-2-24. */public class ProxyListener implements TestController.TestListener {    private WeakReference<TestController.TestListener> mTestListenerWeakReference;    public ProxyListener(TestController.TestListener testListener) {        mTestListenerWeakReference = new WeakReference<TestController.TestListener>(testListener);    }    @Override    public void onTest() {        if (mTestListenerWeakReference.get() != null) {            mTestListenerWeakReference.get().onTest();        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

MainActivity还是依旧实现TestListener

public class MainActivity extends Activity implements TestController.TestListener {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        TestController.getsInstance().setListener(new ProxyListener(this));        TestController.getsInstance().run();    }    @Override    public void onTest() {    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

运行,然后马上按下返回键,这时候,我们看到,不会再有内存泄漏的情况出现了。

实际上,这里相当于实现了一个代理类,它持有Listener的引用,只不过相比于普通的代理类,Listener的引用变成了弱引用,而不是强引用。然而,就是这样小小的改动,就这样巧妙地从外部解决的内存泄漏的问题!

这种思路也是来自的同部门的研发大神bq,只能说学无止境,拜服。

最后demo地址:https://github.com/82367825/leaedMemoryDemo



转载自:http://blog.csdn.net/z82367825/article/details/57096258

原创粉丝点击