Android常见的泄露以及解决策略
2016-03-28 22:55
423 查看
1. 简介
在整个Android开发过程中,内存泄露是导致OOM的一个重点因素。大概意思就是:GC无法回收原本应该被回收的对象,这个对象就引发了内存泄露。那有什么危害呢?手机的内存大小是有限的,如果不能释放的话,你就无法创建新的对象,你的新界面等等就无法正常运行,然后程序就OOM了(OutOfMemory)。
2. OOM以及内存泄露
OOM通俗点讲就是,你家里有2个厕所,本来你和你老婆用的话,都是够用的,有一天你不小心造人了,从此家里有了1+1=3个人了。一天的凌晨,你起床,发现肚子不舒服,“我要上厕所!”(请求系统分配空余内存给当前app)。咦,老婆你在里面啊,那我去下一家(系统开始分析你需要的内存以及空余内存,准备分配)。啊,儿子你也蹲着啊(完了,2个厕所都被人占着了,内存不足,boom!boom!你此时肯定是奔溃的,拉屎忍不住了,肯定要异常奔溃了。OOM,app程序异常退出了)。
那么内存泄露呢?比如你买了一堆可擦除的画板(画板=手机,画板空间有限=内存有限),刚开始你拿去画了一会画,慢慢的用了不少画板。此时你还在继续画,发现没有新的画板了,只好找刚才用过的,但是你发现用错了画笔,导致擦不掉!(不正常的使用context等导致内存泄露了,GC回收不了内存。)而且所以找遍了所有的画板,都没有找到空白的地方(分配不了新的空余内存给app),只好结束此次画画的事情(内存泄露导致内存不足,这个app程序OOM)。
3. 配置
本篇是初级篇,就不过多描述理论性的东西了,大牛的文章都写过,本人就不再进行描述了。那么我们如何解决内存泄露的问题呢?对于小白的我们肯定想有一款简单易用、快速定位的内存泄露插件,那么我推荐LeakCanary傻瓜式检测工具给大家。
ok,第一步肯定是怎么在项目里引用这个呢?首先,Android studio的项目引用第三方库的方法你得知道。在build.gradle里如下2个引用。什么,为什么有2个?其实有3个呢,原因很简单,你总不会正式发布的包也加内存泄露吧?当然也可以正式发布时,把相关引用全都干掉。
引用完了,咱们开始做一些初始化操作。在你的Application的实现类写下下面2句。
然后在你的基类里加上这一句
常见的泄露基本都是上下文的持有导致的,所以应对这一点,我采用持有弱引用的方式。弱引用,只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。此外,刚才的回调接口也需要设置null。这样在activity销毁时onDestroy方法里调用下面的destroy方法即可。重要的一点是,网络请求在界面销毁时最好进行cancel操作,比如volly框架的根据请求tag进行取消,这样也是尽量避免接口回调导致的内存泄露。此外,动画在界面离开时或者销毁时,同时进行暂停或者销毁。
还有一种常见的就是handler的使用。通常我们直接new一个就完事了,Android studio会显示大大的黄色警告区域。此时就需要利用静态内部类以及弱引用解决了。平常需要context的地方就可以用 mActivity.get()代替了。
在App不可避免的是webview加载网页了,然后这个也是一个可怕的开始。webview界面内存泄露解决,不要xml设置webview,而是以代码创建view对象的方式进行初始化,并且界面销毁时调用 destroy等方法 。
此外,Toast最好用ApplicationContext,如果用activity的context,吐司还没结束的时候退出当前界面,这是内存也会泄露。
至于context与bitmap之间的点滴,我用了fresco图片加载框架,还算好。而且这方面资料也不少,我暂时也不准备描述了。
好了,LeakCanary的简单使用就到这里了。下次再来深度分析内存泄露的点点滴滴。
在整个Android开发过程中,内存泄露是导致OOM的一个重点因素。大概意思就是:GC无法回收原本应该被回收的对象,这个对象就引发了内存泄露。那有什么危害呢?手机的内存大小是有限的,如果不能释放的话,你就无法创建新的对象,你的新界面等等就无法正常运行,然后程序就OOM了(OutOfMemory)。
2. OOM以及内存泄露
OOM通俗点讲就是,你家里有2个厕所,本来你和你老婆用的话,都是够用的,有一天你不小心造人了,从此家里有了1+1=3个人了。一天的凌晨,你起床,发现肚子不舒服,“我要上厕所!”(请求系统分配空余内存给当前app)。咦,老婆你在里面啊,那我去下一家(系统开始分析你需要的内存以及空余内存,准备分配)。啊,儿子你也蹲着啊(完了,2个厕所都被人占着了,内存不足,boom!boom!你此时肯定是奔溃的,拉屎忍不住了,肯定要异常奔溃了。OOM,app程序异常退出了)。
那么内存泄露呢?比如你买了一堆可擦除的画板(画板=手机,画板空间有限=内存有限),刚开始你拿去画了一会画,慢慢的用了不少画板。此时你还在继续画,发现没有新的画板了,只好找刚才用过的,但是你发现用错了画笔,导致擦不掉!(不正常的使用context等导致内存泄露了,GC回收不了内存。)而且所以找遍了所有的画板,都没有找到空白的地方(分配不了新的空余内存给app),只好结束此次画画的事情(内存泄露导致内存不足,这个app程序OOM)。
3. 配置
本篇是初级篇,就不过多描述理论性的东西了,大牛的文章都写过,本人就不再进行描述了。那么我们如何解决内存泄露的问题呢?对于小白的我们肯定想有一款简单易用、快速定位的内存泄露插件,那么我推荐LeakCanary傻瓜式检测工具给大家。
ok,第一步肯定是怎么在项目里引用这个呢?首先,Android studio的项目引用第三方库的方法你得知道。在build.gradle里如下2个引用。什么,为什么有2个?其实有3个呢,原因很简单,你总不会正式发布的包也加内存泄露吧?当然也可以正式发布时,把相关引用全都干掉。
dependencies { debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3' releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3' }
引用完了,咱们开始做一些初始化操作。在你的Application的实现类写下下面2句。
/** * 内存泄露检测 */ private RefWatcher refWatcher; public static RefWatcher getRefWatcher(Context context) { TTApplication application = (TTApplication) context.getApplicationContext(); return application.refWatcher; } @Override public void onCreate() { super.onCreate(); refWatcher = LeakCanary.install(this);//内存泄露检测 }
然后在你的基类里加上这一句
@Override public void onDestroy() { RefWatcher refWatcher = TTApplication.getRefWatcher(getActivity()); refWatcher.watch(this);//内存泄露检测 }
常见的泄露基本都是上下文的持有导致的,所以应对这一点,我采用持有弱引用的方式。弱引用,只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。此外,刚才的回调接口也需要设置null。这样在activity销毁时onDestroy方法里调用下面的destroy方法即可。重要的一点是,网络请求在界面销毁时最好进行cancel操作,比如volly框架的根据请求tag进行取消,这样也是尽量避免接口回调导致的内存泄露。此外,动画在界面离开时或者销毁时,同时进行暂停或者销毁。
private WeakReference<ShoppingCartActivity> mBaseActivity; private IShoppingCartView mIShoppingCartView; public ShoppingCartPresenter(ShoppingCartActivity context, IShoppingCartView iShoppingCartView) { mBaseActivity = new WeakReference<>(context); mIShoppingCartView = iShoppingCartView; } @Override public void destroy() { mIShoppingCartView = null; }
还有一种常见的就是handler的使用。通常我们直接new一个就完事了,Android studio会显示大大的黄色警告区域。此时就需要利用静态内部类以及弱引用解决了。平常需要context的地方就可以用 mActivity.get()代替了。
static class CommentHandler extends Handler { WeakReference<HomeActivity> mActivity; CommentHandler(HomeActivity activity) { mActivity = new WeakReference<>(activity); } public void handleMessage(Message msg) { super.handleMessage(msg); } }
在App不可避免的是webview加载网页了,然后这个也是一个可怕的开始。webview界面内存泄露解决,不要xml设置webview,而是以代码创建view对象的方式进行初始化,并且界面销毁时调用 destroy等方法 。
WebView mWebView =new WebView (this); @Override protected void onDestroy() { if (mWebView != null) { mWebView.getSettings().setBuiltInZoomControls(true); mWebView.setVisibility(View.GONE);// 把destroy()延后 mWebView.removeAllViews(); mWebView.destroy(); } super.onDestroy(); }
此外,Toast最好用ApplicationContext,如果用activity的context,吐司还没结束的时候退出当前界面,这是内存也会泄露。
至于context与bitmap之间的点滴,我用了fresco图片加载框架,还算好。而且这方面资料也不少,我暂时也不准备描述了。
好了,LeakCanary的简单使用就到这里了。下次再来深度分析内存泄露的点点滴滴。
相关文章推荐
- Android——Intent.setClass()
- APK反编译
- Android进程优先级部分整理与理解
- android graphic(15)—fence
- $《第一行代码:Android》读书笔记——第5章 Broadcast
- Android 广播学习总结
- Android layout 布局 属性详解
- android 点击复制粘贴板
- 欢迎使用CSDN-markdown编辑器
- [android] 自定义广播事件
- Android系统打印服务插件printservice开发
- Android_Printservice_API_部分翻译
- Android 仿当乐游戏详情页面(二)
- [Android学习]Android中MVP模式初探1
- android,service实例,播放音乐
- android view 动画学习
- AndroidStudio R.java文件丢失的问题
- 关于android中主线程和子线程间的相互通讯
- Android压缩图片并且保存到本地内存卡中
- AndroidStudio项目提交(更新)到github最详细步骤