性能优化(二) 内存溢出& 内存泄漏
内存泄漏& 内存溢出
内存泄漏&内存溢出的区别
- 内存泄漏 memory leak
- 系统无法释放已经申请的内存
- 内存溢出 out of memory (内存不足)
- 申请内存时系统没有足够的内存供其使用
- 内存泄露是导致内存溢出的原因之一,内存泄漏过多 最终会导致内存溢出
- 内存泄露可以通过完善代码来避免;内存溢出可以通过调整配置来减少发生频率,但无法彻底避免。
内存泄漏分类
- 常发性内存泄漏
- 内存泄漏的代码经常被执行到
- 偶发性内存泄漏
- 内存泄漏的代码在某些特定条件下执行
- 隐式内存泄漏
- 程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存,多表现在服务端,因为服务端24*n运行
- 一次性内存泄漏
- 内存泄漏的代码在程序运行过程中只执行一次
导致内存泄漏的原因& 解决办法
总体来说 都属于资源未释放
-
长生命周期持有短声明周期的引用
- 比如
单例模式
持有Activity的context
- 解决办法
- 将activity的context 换成ApplicationContext
- 比如
-
非静态内部类 和 匿名类
都会潜在的引用它们所属的外部类-
但是,静态内部类却不会。如果这个非静态内部类实例做了一些耗时的操作,就会造成外围对象不会被回收,从而导致内存泄漏。
-
解决办法
-
将内部类定义成静态类即可
-
如果有强引用Activity中的属性,则将该属性的引用方式改为弱引用;
-
new WeakReference<View>("Activity中的属性");
-
-
在业务允许的情况下,当Activity执行onDestory时,结束这些耗时任务;
-
-
-
-
-
连接资源没有被关闭,图片资源没有被释放,View 没有被销毁,属性动画没有close
- 比如 数据库的Cousor ,Io 流 ,网络连接
- 解决方案
- 在不用时将资源调用close关闭即可 一般try catch finally 中的finally中关闭 此类连接
- 解决方案
- Bitmap 图片资源没有释放
- 解决方案
- 不用时调用recycle 释放即可
- 解决方案
- 比如 数据库的Cousor ,Io 流 ,网络连接
-
集合数据未及时清理导致的内存泄漏
- 当集合数据过大导致内存泄漏
- 解决方案
- 当集合中数据不在使用,及时清空
- 解决方案
- 当集合数据过大导致内存泄漏
-
注册API中的监听器,回调没有解除注册
-
例如 动态注册广播,在activity退出时就要解除注册
- 解决方案
- 及时解除注册
- 解决方案
-
例如WebView sdk5.1会产生内存泄漏
-
原因AwContents 类中注册了component callbacks,但是未正常反注册而导致的。导致
WebView的ContentViewCore
中的成员变量mContainerView
引用着AccessibilityManager
的mAccessibilityStateChangeListeners
导致activity
不能被回收造成了泄漏。 -
具体原因
mAccessibilityStateChangeListeners
没移除mComponentCallbacks
没有解除注册-
在
onAttachedToWindow
的时候调用mContext.registerComponentCallbacks(mComponentCallbacks)
进行注册,
在onDetachedFromWindow
中反注册 -
但是在
onDetachedFromWindow
中有可能直接返回所以有可能不会执行反注册 -
public void onDetachedFromWindow() { if (isDestroyed()) return; if (!mIsAttachedToWindow) { Log.w(TAG, "onDetachedFromWindow called when already detached. Ignoring"); //直接返回 return; } mIsAttachedToWindow = false; hideAutofillPopup(); nativeOnDetachedFromWindow(mNativeAwContents); mContentViewCore.onDetachedFromWindow(); updateHardwareAcceleratedFeaturesToggle(); if (mComponentCallbacks != null) { mContext.unregisterComponentCallbacks(mComponentCallbacks); mComponentCallbacks = null; } mScrollAccessibilityHelper.removePostedCallbacks(); mNativeGLDelegate.detachGLFunctor(); }
-
解决方案
-
1 . 在销毁
webview
前一定要onDetachedFromWindow
,我们先将webview
从它的父view中移除再调用destroy方法,代码如下:@Override protected void onDestroy() { super.onDestroy(); if (mWebView != null) { ViewParent parent = mWebView.getParent(); if (parent != null) { ((ViewGroup) parent).removeView(mWebView); } mWebView.removeAllViews(); mWebView.destroy(); mWebView = null; } }
-
- 利用framelauyout动态加载webview destory中先移除 在销毁 创建webview 用Application的context
-
- 单独开进程
-
activity中指定 进程名
-
导致问题 application多次启动 可以获取当前进程名称判断是否需要初始化设置
-
-
-
-
-
Handler
和AsyncTask
导致的内存泄漏-
Handler 解决方案
-
静态内部类 将Handler 定义为静态内部类
- java总静态内部类不持有外部类引用
-
弱引用 将引用的activity中的属性保存为弱引用 比如引用了Activity
new WeakReference<Activity>(activity);
-
移除所有信息调用
removeCallbacksAndMessages
-
Handler产生原因
- 当我们
Activity
销毁的时,有可能Handler
还在继续等待执行未完成message
,它持有Activity的引用不能被回收,因此当我们Activity销毁的时候要立即remove掉所有的消息和回调
,以避免发生内存泄漏。 - message 持有了handler对象
- 当我们
-
-
AsnycTask 解决方案
- 将其定义成静态内部类
- 引用activity内的属性 保存为弱引用 参考Handler
- AsyncTask产生内存泄漏原因
- 当我们
Activity
销毁的时,有可能Timer
还在继续等待执行TimerTask
,它持有Activity的引用不能被回收,因此当我们Activity销毁的时候要立即cancel
掉Timer
和TimerTask
,以避免发生内存泄漏。
- 当我们
-
-
String字符串拼接的问题
- String 每一次拼接都会创建一个新的对象,造成内存占用过大
- 解决方案
- 使用
StringBuffer
- 使用
-
改变哈希值
- 当对象被存储进
HashSet
集合后,就不能在对这个对象中参与计算哈希值的字段进行修改,一旦进行修改对象的哈希值会发生变化- 这种情况下,即使
Contains
方法使用当前对象的当前引用也不能检索到对象,会返回找不到该对象,也会导致该对象一直在Hashset中,无法删除,如果数据过多就会导致内存泄漏
- 这种情况下,即使
- 当对象被存储进
-
listview 构造Adapter时,没有使用缓存的 convertView
- 解决方案 在实现adapter时 使用convertView缓存
总结
- 应保持良好的编程习惯,根据需求及时的释放资源,根据需求选择适用的数据集合,比如android提供的SparseArray
和
ArrayMap,比hashmap占用的内存更小
内存溢出 导致的原因
-
内存泄漏过多导致
-
系统分配内存过小
- 可能还有其他的,欢迎留言
内存溢出解决方案
-
保持良好的代码习惯,及时释放资源
-
向系统申请更大的内存空间
-
在
AndroidManifest.xml
中设置 -
android:largeHeap=”true” 为true 申请512M, false 申请192M
-
-
使用更轻量级的数据结构
- 使用轻量级的数据结构,替代hashmap,用sparseArray,Hashmap会导致一些没必要的自动装箱和拆箱。
-
避免频繁的创建对象
- 比如自定义view ondraw 就应该避免创建对象的操作
-
资源文件图片与目录不匹配
- ldpi QVGA (240×320)
- mdpi HVGA (320×480)
- hdpi WVGA (480×800)
- FWVGA (480×854)
- xhdpi 720P(1280x720)
- xxhdpi 1080p(1920x1080 )
- xxxhdpi 4K(3840×2160)
上一篇: 性能优化-service进程防杀
下一篇: 网站架构的性能优化