Android 内存优化使用profile 和 MAT 工具进行内存泄漏检测
内存抖动 & 内存泄漏 & 内存溢出(OOM)
内存抖动
含义:短时间内有大量对象创建销毁,它伴随着频繁的GC。
查看:可以使用android studio自带的profile工具检测。
现象:在profile中的内存图像就像是心电图一样,忽上忽下,如下图所示:
常见场景:循环使用字符串拼接,比如我们项目的日志打印等
预防内存抖动方法:
避免在循环中创建对象,能复用的尽量复用。
避免在频繁调用的方法中创建对象,如自定义view中的onDraw()等方法中创建画笔。
获取对象尽量从对象池中获取,如Handler获取Message对象应使用obtain()方法获取了。
内存泄漏
程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费。
长生命周期对象持有短生命周期对象强引用,从而导致短生命周期对象无法被回收!
查看:使用profile工具检测内存情况,重复执行进入然后退出一个activity,看activity实例是否还存在。如果activity实例还存在,很可能就出现了内存泄漏。
现象:反复进入A,然后退出A ,执行三次,可以看到A 的实例存在两个。如下图,VideoPlayerActivity:
这就说明我们的activity并没有被销毁,至少目前是这样的。至于究竟会不会内存泄漏,就需要接下来使用另一款工具配合使用了。
如何判断内存泄漏:
使用可达性分析法
通过一系列称为“GC Roots”的对象作为起始点,从这些节点向下搜索,搜索所有的引用链,当一个对象到GC Roots没有任何引用链(即GC Roots到对象不可达)时,则证明此对象是不可用的。也就会被回收。
何为GC Roots 对象,一般静态变量就是gc root对象,可以理解成生命周期很长的对象。
如何预防内存泄漏:
使用 软引用、弱引用间接的持有对象的引用。
软引用:
定义一些还有用但并非必须的对象。对于软引用关联的对象,GC不会直接回收,而是在系统将要内存溢出之前才会触发GC将这些对象进行回收。
弱引用 :
同样定义非必须对象。被弱引用关联的对象在GC执行时会被直接回收。
造成内存泄漏的常见场景:
使用集合时,例如add一个监听器,我们必须要手动remove掉。
使用静态成员变量/单利对象时,如果持有短生命周期对象的引用(Activity)将导致短生命周期对象无法被释放。
进行文件io操作时,没有close()。最好写在finally{ }里面;
android 系统bug、第三方类库造成的内存泄漏。
内存溢出
内存溢出(Out Of Memory,简称OOM)是指应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于能提供的最大内存。此时程序就运行不了,系统会提示内存溢出,有时候会自动关闭软件,重启电脑或者软件后释放掉一部分内存又可以正常运行该软件
频繁的出现内存抖动或者大量内存泄漏很有可能就会导致内存溢出(OOM)。
Android 中的垃圾回收器 CMS
android 中使用的垃圾回收器 叫做CMS ,下面简单介绍下他的垃圾回收算法。
新生代对象
新生代对象采用的是复制算法,当大对象也可能直接进入老年代。
老年代对象
老年代对象采用的是标记-清除算法,所以频繁的内存抖动,会造成内存碎片化,最后可能我们需要加载一个大对象的时候,就OOM 了。
简单介绍下CMS垃圾回收算法,如果不熟悉的建议请先百度jvm 垃圾回收机制相关知识。
实战 内存泄漏
配置环境
android studio
eclipse memory analyzer (mat)
下载mat
下载地址点我
选择相应版本进行下载安装。
配置mat 环境,因为从 android profile直接获取到的hprof文件格式与mat的格式不兼容,所以需要使用工具转换一下
win 环境配置,请自行百度,由于本人用的Mac 所以这里只写Mac的配置
打开终端输入:echo
H
O
M
E
继
续
输
入
:
t
o
u
c
h
.
b
a
s
h
p
r
o
f
i
l
e
继
续
输
入
:
o
p
e
n
−
e
.
b
a
s
h
p
r
o
f
i
l
e
在
打
开
的
b
a
s
h
文
件
中
输
入
:
e
x
p
o
r
t
P
A
T
H
=
HOME 继续输入:touch .bash_profile 继续输入: open -e .bash_profile 在打开的bash文件中输入: export PATH=
HOME继续输入:touch.bashprofile继续输入:open−e.bashprofile在打开的bash文件中输入:exportPATH={PATH}:/Users/用户名/你的sdk路径/platform-tools
最后输入: source .bash_profile
没有6了,已经成功配置了。
使用profile获取内存分析文件
名字随便了,怎么方便怎么来
打开终端,进行文件转换
转换格式 : hprof-conv before.hprof after.hprof
我们这里输入 : hprof-conv memory-99.hprof 66.hprof
能看懂吧,吧我们的源文件 -99 转换成 -66文件,
注意了 : 需要进入-99 所在的文件目录,要不然会报错找不到文件
打开mat工具,导入我们的-66 文件
打开后可以看到这样的界面
点击红框的选项,这个是进行内存泄漏分析的
下面就是这段时间所产生的对象,点击红框 可以直接搜索你要分析的对象
这里找到了我们的VideoPlayerActivity
鼠标右键选择
可以看到,意思就是我们排除掉软、弱、虚引用,因为这几种是不会造成内存泄漏的,可以不用管它,我们只需要看排除后还有没引用存在,有的话 那就是强引用了,也就发生了内存泄漏了。
继续看我们的结果:
点击后,发现里面存在数据,那就说明我们有内存泄漏发生了,也就是为什么上面我们已经退出了,profile里面还有三个activity的存在,刚刚上面那张图右侧也有显示有3个activity对象存在。
我们一一展开,看看到底哪里内存泄漏了
可以看到,我们的Avtivity 作为mContext 变量被我们的自定义CoverVideoPlayerView 持有了,那也就是说,因为我们的自定义View不能被gc回收,所以activity也无法被回收。
那就继续看,为什么自定义view无法被回收,可以看到,this$0,这表示在自定义view的内部有一个非静态内部类,而非静态内部类是默认持有外部类的引用的,也就是我们的,mNetChangeListener对象,这个就熟悉了吧,肯定是new 一个匿名内部类啊,
继续看,这个内部类又被NetInfoModeule引用了,我丢,然后继续往上看
相关文章
- android 置灰不可点击,Android Studio 运行按钮灰色的完美解决方法
- android开机动画多长时间_Android开机动画及黑屏[通俗易懂]
- 测试android sdk是否安装成功,配置Android SDK
- android sdk manager安装,Android SDK Manager安装过程
- android 验证码短信验证码,Android短信验证码倒计时验证的2种常用方式
- android telephony 原理解析与开发指南_Android逆向pdf
- 面向初学者的 Android 应用开发基础知识
- android应用程序_chrome Android
- Android resource linking failed_android sdk location should not
- Android 关于 Snackbar 基本使用
- 自研的内存分析利器开源了!Android Bitmap Monitor 助你定位不合理的图片使用
- 【Android 内存优化】图片文件压缩 ( Android 原生 API 提供的图片压缩功能能 | 图片质量压缩 | 图片尺寸压缩 )
- 【Android 内存优化】Android 工程中使用 libjpeg-turbo 压缩图片 ( 初始化压缩对象 | 打开文件 | 设置压缩参数 | 写入压缩图像数据 | 完成压缩 | 释放资源 )
- 【Android 内存优化】Bitmap 图像尺寸缩小 ( 设置 Options 参数 | inJustDecodeBounds | inSampleSize | 工具类实现 )
- 【Android 内存优化】Bitmap 内存缓存 ( Bitmap 缓存策略 | LruCache 内存缓存 | LruCache 常用操作 | 工具类代码 )
- 【Android 逆向】修改运行中的 Android 进程的内存数据 ( 使用 IDA 分析要修改的内存特征 | 根据内存特征搜索修改点 | 修改进程内存 )
- 【Android 逆向】Android 进程代码注入原理 ( 进程注入原理 | 远程调用流程 | 获取函数地址 | 设置 IP 寄存器 | mmap 申请内存 | 设置 SP 寄存器 )
- 【Android 逆向】Android 进程注入工具开发 ( 总结 | 源码编译 | 逆向环境搭建使用 | 使用进程注入工具进行逆向操作 ) ★★★
- 【Android 逆向】Android 逆向通用工具开发 ( Windows 平台运行的控制台应用程序类型 | 编译 Windows 平台运行的 Android 逆向程序 )
- 【Android 逆向】启动 DEX 字节码中的 Activity 组件 ( DEX 文件准备 | 拷贝资源目录下的文件到内置存储区 | 配置清单文件 | 启动 DEX 文件中的组件 | 执行结果 )
- 【Android Gradle 插件】Gradle 依赖管理 ⑧ ( implementation fileTree 引入jar文件依赖 | implementation files 引入文件依赖 )
- Android性能优化-内存泄漏的8个Case详解手机开发
- Android约束布局ConstraintLayout详解手机开发
- Android控制文字水平间距android:letterSpacing详解手机开发
- [android] 手机卫士来电显示号码归属地详解手机开发
- [android] 创建模拟器遇到的常见错误详解手机开发
- 合作汽车厂商:Android Auto与CarPlay将共存
- Android递归方式删除某文件夹下的所有文件(.mp3文件等等)