0、序
最近新版本上线,随着用户增多,发现5.0上的OOM类型的错误异常的多,但是4.4上除了一些低端机型都没有出现同样的问题,作为一个开发人员怎么能不找出原因呢?!!
1、工具
对于内存泄露这种问题,当然要祭出LeakCanary这种查内存泄露的神器啦。
使用的方式也很简单,用maven就行。使用方法如下,在app的build.gradle下面加入你要用的版本。因为自己项目正式发布时不会用这个,所以只用了debug版本的。
dependencies {
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'
}
public class ExampleApplication extends Application { @Override public void onCreate() { super.onCreate(); LeakCanary.install(this); } }ok,搞定。但是如果你还想要自己定义监控的页面或者变量,可以参考 https://github.com/square/leakcanary#how-do-i-use-it
虽然这么想,但是我觉得作为一个程序猿应该先想到可能还是自己的代码有问题,而不能盲目的猜测。
于是用LeakCanary一查,发现是动图播放控件没有释放,一环接一环的影响了Activity的释放,最终内存泄露了。但是一看自己的代码,不管在detach或者切换时都已经做了释放,不可能出现未释放的情况。
接下去,我就在recyclerView里面找原因,觉得会不会是recyclerView并没有detach掉列表项,因为之前找到了很多个recyclerView的bug,于是乎就打印log查找是否detach,但是发现每一项都被detach了。同时我注意到另一个问题,当我只是慢速滑动的时候,LeakCanary并不显示内存泄露,而是在我快速滑动的时候,LeakCanary就显示内存泄露了。我想会不会是快速滑动导致detach失效呢?但并不是这样的,在快速滑动过程中,每一项都有被bind到,也同时会被detach。
由于之后没有头绪,甚至就试着关闭快速滑动。阳台上走了一圈,突然灵感迸发,如果是内存泄露,会不会是线程没有停止,于是就查看lib,然后打印日志,果然在快速滑动下线程并没有被关闭,而是一直在输出log日志。因为在线程中持有了一个Handler对象,Handler对象又被控件所持有,结果就恶性循环导致内存没法释放。但是改成WeakReference的Handler,发现也存在泄露问题,说明这个线程在其他地方被启动了。查找了app module下所有启动的地方,发现并没有不符合规范的地方,后来又去lib下面查找,才发现在图片下载完成之后竟然直接就启动线程播放了。。。。。于是把线程开始全部改成代码控制。
3、结论
不要在一个线程结束后有紧接着调用一个死循环的线程,除非你有特定的条件去触发线程停止,否则最好还是在可控的范围内调用线程,毕竟这东西是不可控的,就算你退出程序,还是会运行。
Over 。