- 一:App内存组成以及限制
- 二:什么是OOM?
- 三:Android 内存分析命令介绍
- 四,内存三大问题
- 五,MAT工具(查找具体内存泄漏点的)
- 六, LeakCanary
- 七:Android内存泄漏常见场景以及解决方案
- 八:Bitmap (解决这个基本是99%的解决)
- 九:总体思想
一:App内存组成以及限制
Android给每个APP分配一个VM,让App运行在dalvik上,这样app奔溃了也不会影响系统。系统给VM 分配了一定的内存大小,如果应用超过了vm最大内存,就会出现
内存溢出 crash;
由程序控制操作的内存空间在heap上 分java heapsize 和 native heapsize
java申请的内存在vm heap 上 所有如果java申请的内存大小超过了vm逻辑内存限制就会内存溢出的异常;
native 层 内存申请不受器限制 native层 native process 对内存带下的限制;
二:什么是OOM?
1,强引用,软引用,弱引用,虚引用的区别;
软引用内存不足的时候才会回收,弱引用,gc扫描到了就会回收;虚引用相当于没有引用;
三:Android 内存分析命令介绍
常用的内存调优分析命令:
- dumpsys meminfo
- procrank
- cat /proc/meminfo
- free
- showmap
- vmstat
四,内存三大问题
1,内存抖动
内存波动图形呈锯齿状,GC导致卡顿; 比如,自定view的时候,在ondraw等地方频繁创建对象,系统无连续可用的内存空间,就频繁GC,导致卡顿;
2,内存泄漏
在当前应用周期内不再使用的对象被GC roots引用,导致不能回收,使实际可用内存变小;
3,内存溢出
即OOM,OOM时会导致程序异常,Android设备出厂以后,java虚拟机对单个应用的最大内存分配就确定下来了,超过这个值就会OOM;
OOM时不时一定代表内存不够了吗?
(1)Java堆内存溢出,
(2)无足够连续内存空间(整体加起来够可是,无连续的),
(3)FD数量超过限制(fd文件句柄)
(4)线程数量超出限制(每个应用的线程数是有限制的,小于1000个,这种情况可以用线程池,业务有问题,都1000个线程了),
(5)虚拟内存不足
五,MAT工具(查找具体内存泄漏点的)
六, LeakCanary
https://github.com/square/leakcanary
1, LeakCanary是如何安装的?
- 注册app:contentprovider contentprovider.oncreate 比 application.oncreate 更先执行
- 2,apk 打包流程 mergeAndroidManifest.xml -> app AndroidManifest
2, LeakCanary检测Activity退出的原理
1,ActivityLifecycleCallbacks 生命周期回调去检测
2,Reference弱引用 Reference弱Queue
七:Android内存泄漏常见场景以及解决方案
1、资源性对象未关闭
对于资源性对象不再使用时,应该立即调用它的close()函数,将其关闭,然后再置为null。例如Bitmap等资源未关闭会造成内存泄漏,此时我们应该在Activity销毁时及时关闭。
2、注册对象未注销
例如BraodcastReceiver、EventBus未注销造成的内存泄漏,我们应该在Activity销毁时及时注销。
3、类的静态变量持有大数据对象
尽量避免使用静态变量存储数据,特别是大数据对象,建议使用数据库存储。
4、单例造成的内存泄漏
优先使用Application的Context,如需使用Activity的Context,可以在传入Context时使用弱引用进行封装,然后,在使用到的地方从弱引用中获取Context,如果获取不到,则直接return即可。
5、非静态内部类的静态实例
该实例的生命周期和应用一样长,这就导致该静态实例一直持有该Activity的引用,Activity的内存资源不能正常回收。此时,我们可以将该内部类设为静态内部类或将该内部类抽取出来封装成一个单例,如果需要使用Context,尽量使用Application Context,如果需要使用Activity Context,就记得用完后置空让GC可以回收,否则还是会内存泄漏。
6、Handler临时性内存泄漏
在Queue中存在的时间过长,就会导致Handler无法被回收。如果Handler是非静态的,则会导致Activity或者Service不会被回收。并且消息队列是在一个Looper线程中不断地轮询处理消息,当这个Activity退出时,消息队列中还有未处理的消息或者正在处理的消息,并且消息队列中的Message持有Handler实例的引用,Handler又持有Activity的引用,所以导致该Activity的内存资源无法及时回收,引发内存泄漏。解决方案如下所示:
- 1、使用一个静态Handler内部类,然后对Handler持有的对象(一般是Activity)使用弱引用,这样在回收时,也可以回收Handler持有的对象。
- 2、在Activity的Destroy或者Stop时,应该移除消息队列中的消息,避免Looper线程的消息队列中有待处理的消息需要处理。
需要注意的是,AsyncTask内部也是Handler机制,同样存在内存泄漏风险,但其一般是临时性的。对于类似AsyncTask或是线程造成的内存泄漏,我们也可以将AsyncTask和Runnable类独立出来或者使用静态内部类。
7、容器中的对象没清理造成的内存泄漏
在退出程序之前,将集合里的东西clear,然后置为null,再退出程序
8、WebView
WebView都存在内存泄漏的问题,在应用中只要使用一次WebView,内存就不会被释放掉。我们可以为WebView开启一个独立的进程,使用AIDL与应用的主进程进行通信,WebView所在的进程可以根据业务的需要选择合适的时机进行销毁,达到正常释放内存的目的。
9、使用ListView时造成的内存泄漏
在构造Adapter时,使用缓存的convertView。
八:Bitmap (解决这个基本是99%的解决)
https://www.jianshu.com/p/59cb10228f6c
九:总体思想
1,设备分级
2.Bitmap优化
统一图片库
线上线下监控 hook
glide:官方推荐
网友评论