内存泄漏,当资源对象长期(例如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() { } }我们看到,MainActivity实现了TestController.TestListener接口,这时候相当于TestController持有了MainActivity的引用,如果此时我们按下返回键,回到手机桌面,这时候就出现了应用内存泄漏。借助leakcanary库我们可以看到:
由于TestController内部开启了线程,同时持有着MainActivity的引用,导致MainActivity实例对象无法被释放。
如何解决这种类型的内存泄漏,通常的思路是通过弱引用。当一个对象只有被弱引用指向的时候,那么它就随时会垃圾回收系统回收。
通常一个SDK内部出现了内存泄漏,我们第一个的想法就是让SDK内部增加解决的方法:
然而,有时候,我们不能总期待着别人帮我们去解决这个问题,由于时间紧急,我们可能自己去解决这个内存泄漏的问题。最理想的情况是,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(); } }}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() { }}运行,然后马上按下返回键,这时候,我们看到,不会再有内存泄漏的情况出现了。
实际上,这里相当于实现了一个代理类,它持有Listener的引用,只不过相比于普通的代理类,Listener的引用变成了弱引用,而不是强引用。然而,就是这样小小的改动,就这样巧妙地从外部解决的内存泄漏的问题!
这种思路也是来自的同部门的研发大神bq,只能说学无止境,拜服。
最后demo地址:https://github.com/82367825/leaedMemoryDemo
新闻热点
疑难解答