首页 > 系统 > Android > 正文

Android-内存泄漏巧妙解决

2019-11-07 23:23:55
字体:
来源:转载
供稿:网友

内存泄漏

内存泄漏,当资源对象长期(例如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实例对象无法被释放。

解决思路:

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

1)TestController内部解决

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

手动释放引用
public class TestController { ... public void setListener(TestListener testListener) { this.mTestListener = testListener; } public void release() { this.mTestListener = null; } ...}
将对象引用改为弱引用
public class TestController { ... private WeakReference<TestListener> mTestListenerWeakReference; public void setTestListener(TestListener testListener) { this.mTestListenerWeakReference = new WeakReference<TestListener>(testListener); } ...}

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(); } }}

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


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表