性能优化之内存优化

版权声明:本博客仅用于学习交流,欢迎转载,但请注明作者和出处 https://blog.csdn.net/weixin_37577039/article/details/82596454

性能优化之内存优化


计算 APP 获得的最大内存分配值

Runtime rt=Runtime.getRuntime();
long maxMemory=rt.maxMemory();
Log.i("maxMemory:",Long.toString(maxMemory/(1024*1024)));

内存泄漏

一、内存泄漏查看

1 生成.prof文件
AS 内自带的 Android Profilter 插件
在相应的操作之后,点击 dump java heap 即进行一次GC 进行一次GC后 查看内存情况 (若该释放内存的地方没有释放 则说明存在内存泄漏)
生成.prof文件
点击 左下角的 (Heap Dump左边)的 一个导出箭头 然后保存为 .hprof文件

但是 此时的 .hprof 并非 MAT支持的类型 要转类型


2 转换.prof文件
通过Android-Studio\platform-tools -> hprof-conv.exe 工具转换
在hprof-conv.exe的目录 右键命令行 把要转换的原文件放在同一个文件夹中
然后 用命令

hprof-conv leakfile.hprof newLeakFile.hprof 

即可在本目录生成转换格式的newLeakFile.hprof
然后就可以用MAT打开了


3 使用MAT(MemoryAnalyzer Tool)内存泄漏分析器 进行内存泄漏分析
MAT 中 打开 Histogram(直方图)
可以列出每个类的实例数
可以支持正则表达查找 如找Activity 找某些类与对象

shallow heap 该对象所在的大小 不包括其引用的对象内存
Retained Heap 是 该对象及所引用的对象的总大小 即释放后该对象GC可回收的大小
右键 list objects->:
with incoming references
表示的是 当前查看的对象,被外部应用
with outGoing references
表示的是 当前对象,引用了外部对象
Merge shortest path to gc root (查找gc root)
选择exclude all phanthom weak soft(排除所有 虚 弱 软引用)
如 Activity A 引用了 Activity B
可以在 histogram中 找ActivityB 是否存在 若存在则找被强引用的地方
Merge shortest path to gc root -> exclude all phanthom weak soft 中找到 Activity A引用了


常见内存泄漏情况:
(1) 对象被引用 未被回收 如Activity Context
解决: 找到引用该对象的实例,进行取消引用

(2) 单例模式引起的内存泄漏 单例模式生命周期与Application一致 因此 若将 某个Activity的引用作为单例模式的Context时 Activity被关闭了 但是 单例对象还是引用了该Activity 导致Activity未被释放,而Activity中的如 Bitmap等对象也不能被释放
解决: 将 context.getApplicationContext()传给 单例 作Context

(3)在Acitivity中 写了个非静态内部类 并且 创建了他的静态对象
解决:将内部类封装成单例 context用ApplicationContext

(4)activity中 使用了线程 而线程未执行完
解决:Activity退出时要remove

(5) 属性动画 未 onDestroy或 onStop等时候 进行停止 导致Activity被View引用 无法释放
解决: 及时的停止属性动画

(6) 访问数据库游标未关闭
解决: 访问完数据库关闭游标

(7) 注册的动态广播或者其他监听未及时解注册
解决: 及时解注册


内存溢出
也是可以用上面的MAT进行内存分析

常见的内存溢出优化点:

1 bitmap过大 占据太多内存

查找图片:
查看到 domain Tree (支配树)
然后 看到 android.graphics.Bitmap
点击 左侧看到 图片的 mWidth 和 mHeight 可以知道图片的大小
选中“android.graphics.Bitmap”下方的 “byte[6553600]” 栏,
右键 - Copy - Save Value To File,将bitmap文件保存成后缀名为data的文件
然后用 GIMP工具 打开data后缀的图片
设置宽高 ARGB open即可

优化措施:
1图片太大 而具体的显示区域比较小 导致浪费 因此可以对图片进行缩放加载
BitmapFactory.Options参数,将这个参数的inJustDecodeBounds属性设置为true就可以让解析方法禁止为bitmap分配内存,
返回值也不再是一个Bitmap对象,而是null。虽然Bitmap是null了,
但是BitmapFactory.Options的outWidth、outHeight和outMimeType属性都会被赋值。
这个技巧让我们可以在加载图片之前就获取到图片的长宽值和MIME类型,从而根据情况对图片进行压缩
2 界面被其他对象引用 无法及时释放

3 不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图,
因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存
因此,改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的 source,decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,
无需再使用java层的createBitmap,从而节省了java层的空间

4 及时回收bitmap
虽然GC会回收 但是不保证一定及时

drawble.recycle()
drawble.setCallback(null)

图片压缩处理参考:
https://blog.csdn.net/weixin_37577039/article/details/79777864


常见错误:

1 Error opening heap dump Unknown HPROF Version
解决: 上面第二步要转类型


猜你喜欢

转载自blog.csdn.net/weixin_37577039/article/details/82596454