实践App内存优化:如何有序地作内存分析与优化,Android开发自学技巧

2021年09月15日 阅读数:1
这篇文章主要向大家介绍实践App内存优化:如何有序地作内存分析与优化,Android开发自学技巧,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

Pss: 该进程独占的内存+与其余进程共享的内存(按比例分配,好比与其余3个进程共享9K内存,则这部分为3K)前端

Privete Dirty:该进程独享内存java

Heap Size:分配的内存android

Heap Alloc:已使用的内存git

Heap Free:空闲内存面试

2、Android Profiler

AndroidStduio3.0后Android Profiler变得比以前更强大,内存分析页变得更加直观更加方便,下面是截图:shell

实践App内存优化:如何有序地作内存分析与优化,Android开发自学技巧

  • 进程占用总内存数据库

  • javaHeap:这部份内存大小是有限制的,溢出则会OOM,这部份内存也是咱们分析优化的重点json

  • NativeHeap:native层的 so 中调用malloc或new建立的内存,对于单个进程来讲大小没有限制,因此能够利用在native层分配内存来缓解javaHeap的压力(好比2.3.3以前Android Bitmap的内存分配就是在native层,以后移到javaHeap, 8.0又回到native)缓存

  • Graphics:这部分通常游戏app中用的较多,OpenGL和SurfaceFlinger相关的内存,若没有直接调用到OpenGL,则通常不会涉及到这块内存markdown

  • Stack:栈,了解jvm内存模型的应该都知道

  • Code: 代码,主要是dex以及so等占用的内存

  • Others:就是others啦

因此咱们能够看到事实上咱们能够优化的点有:JavaHeap、NativeHeap、Stack、Code所占用的内存

3、强大的MAT

MAT是作比较细致的内存分析的利器了,功能十分强大,其中的:

Hisogram:Lists number of instances per class

Dominator Tree:List the biggest objects and what they keep alive.

能够很是方便的排序查看当前内存中最占内存的class或者实体对象,并且有一条很是清晰的引用链来查看该对象的持有者,这对内存的分析以及内存泄漏的分析都是很是友好的。

同时MAT支持compare对比功能,将两个.hprof文件导入,都Add to Compare Basket以后便可进行对比,这对于对比某个页面相较与前一页面的内存增量来讲是很是有意义的。

有一点比较不友好的是,MAT须要标准的.hprof文件,因此在AndroidStduio的Profiler中GC后dump出的内存快照还要本身手动利用android sdk platform-tools下的hprof-conv进行转换一下才能被MAT打开。

固然若是以为麻烦的话也能够本身写个脚本执行几条命令来直接完成GC->dump java heap->转换.hprof文件 这个流程:


//adb and hprof-conv

ADB=${ANDROID_HOME}/platform-tools/adb

HPROF_CONV=${ANDROID_HOME}/platform-tools/hprof-conv 

//GC

${ADB} shell pkill -l 10 $(PACKAGE_NAME)


//dump java heap

${ADB} shell "am dumpheap $(PACKAGE_NAME) $(OUT_PATH)" 

//conv hprof

${HPROF_CONV} -z ${FILE_NAME} droid-${FILE_NAME}



2.内存泄漏

------

根据以往经验,其实作内存优化最早要搞定的应该是内存中的大头,这类大头对内存的占用很大,也是内存问题的主要祸首,相对来讲比较容易定位问题,且优化后效果也很是明显,性价比很是高。

> 事实上不少优化都是这样,好比减包大小的优化,也是要先分析出主要大头祸首,好比可能你的包里包含了一张3M大小的无用图片,若是你没找到这种祸首,可能你作了大量的工做去想办法减小无用代码等,最终可能只有几百K的收益。

相对内存来讲,这个大头就是:

*   `内存泄漏`

*   `图片`

因此首先你要确保你的应用里没有存在内存泄漏,而后再去作其余的内存优化。

### 内存泄漏检测

如今内存泄漏的检测已经变得很是简便了,使用App后在Android Profiler中先触发GC而后dump内存快照,以后点击按package分类,就能够迅速查看到你的App目前在内存中残留的class,点击class便可在右边查看到对应的实例以及引用对象。

> 固然你也能够在debug下集成LeakCanary作内存泄漏监控警告

排除内存泄漏后,图片就是另外一个占用内存大头的对象了。

### 图片

对于图片来讲一个是`颜色模式`,检查一下项目里的图片的颜色模式,是否能够下降,好比从RGB\_8888降到RGB\_565,则每张图片能够节省1/2的内存,若是没有使用到透明通道等的话基本上肉眼看不出差异。

还有一个是`下降图片的大小`,可能你的ImageView只有你图片的一半大,则这部份内存就大大浪费了,咱们项目服务端会根据前端的参数作动态切图。

前端也能够经过`下降采样率(inSampleSize)`来达到下降图片占用内存大小的目的,可是这个采样率InSampleSize只能是整数(甚至只能是2的次方),若是inSampleSize=2,则最终内存占用就会是原来的1/4,适用于图片过大不少的状况,对于只是想作小幅度压缩的话,基本没用。

ok,接下来开始作具体的内存分析与稍微细致一点的内存优化。

3.静态内存分析优化

----------

这边说的静态内存指的是在伴随着App的整个生命周期一直存在的那部份内存,也就是打底的,具体获取这部份内存快照的方式是:  

打开App开始重度使用App,基本打开每个主要页面主要功能,而后回到首页,进开发者选项打开"不保留后台活动",而后将咱们的app退到后台。最后GC,dump出内存快照。  

下面是咱们app dump出的内存快照,进行分析后制图以下:

![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly91cGxvYWQtaW1hZ2VzLmppYW5zaHUuaW8vdXBsb2FkX2ltYWdlcy8zODg4NTM4LTNjYjI0NjlmNTkyMmJjNDU_aW1hZ2VNb2dyMi9hdXRvLW9yaWVudC9zdHJpcCU3Q2ltYWdlVmlldzIvMi93LzEwMDAvZm9ybWF0L3dlYnA)

经过对静态内存数据的分析,主要发现了如下几个问题:

**问题1:**?App首页的主图有两张(一张是保底图,一张是动态加载的图),都比较大,并且动态加载的图回来后,保底图并无及时被释放

**优化**:首先是对首页的主图进行颜色通道的改变以及压缩,能够大大下降这两张图所占的内存,而后在动态加载图回来后及时释放掉保底图?`-5M`

**问题2:**?首页底部的轮播背景图占用内存1.6M,且在图片加载回来后,背景图一直没有置空

**优化**:首先通常来讲对背景图的质量并无很高的要求,因此这张背景图是能够被成倍压缩的,而且在图片加载回来后,背景图要及时的释放掉。同时首页的多张轮播图以及其余图片均可以进行颜色模式的改变以及质量压缩。?`-1.6M -4M`

**问题3:**?项目会在App启动时拉一个接口获取一些实验配置,放进单例,在内存分析时发现,这些实验配置居然接近1M

**优化**:排查后发现,接口拉的是整个公司全部部门的实验配置,上千个,这也给遍历拿一个实验配置带来必定的性能损耗,推进接口去改进,只获取当前部门业务须要的实验配置,可节省内存90%以上?`-700K`

**问题4:**?发现几个lottie动画一直没有被回收,而且同一个lottie动画会有几个不一样的实例存在,总共占用内存450K

**优化**:首先要肯定几个lottie动画为何在页面退出后没有被回收,而且同一个动画有几个不一样的实例,很容易就联想到内存泄漏,因为页面没有被销毁,因此致使几个lottie动画也没有被回收,排查下来是项目里的RN页面存在内存泄漏,解决后大概能够节省3-5M内存

**问题5:**?SharePreference在内存里占用了700K的内存

**优化**:因为SP中的东西是会一次性加载到内存里而且保存为静态的,直到App进程结束才会被销毁,因此SP中千万别放大的对象,别图一时方便把对象序列化成json后保存到SP里,优化点就是把已经保存在SP中的一些较大的json字符串或者对象迁移到文件或者数据库缓存。?`-400K`

**问题6:**?埋点数据

**优化**:产品或者运营为了统计数据会在每一个版本不断的增长新埋点,可是也须要按期去清理掉一些过期的不须要的埋点,来适当优化内存以及CPU的压力。

**问题7:**?还有就是一些App里的单例以及一些静态缓存

**优化**:整个看下来在咱们项目中这部分占总体的静态内存其实较小,综合考虑内存状况以及使用的高效性能够进行必定程度的优化,不过这部份内存在App内存紧张时能够选择清理掉他们

咱们能够选择在App退到后台后内存紧张即将被Kill掉时选择释放掉一些内存,如图片的缓存,静态缓存等来自保,具体作法是在Activity中重写`onTrimMemory()`方法(4.0以前是onLowMemory()),在这里面来作内存的释放。

**静态内存优化:约15M**

## 学习交流

**[CodeChina开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》](https://ali1024.coding.net/public/P7/Android/git)**

> ![](https://s2.51cto.com/images/20210912/1631459698673018.jpg)
>
> ![](https://s2.51cto.com/images/20210912/1631459698811594.jpg)

群内有许多来自一线的技术大牛,也有在小厂或外包公司奋斗的码农,咱们致力打造一个平等,高质量的Android交流圈子,不必定能短时间就让每一个人的技术日新月异,但从长远来讲,眼光,格局,长远发展的方向才是最重要的。

35岁中年危机大可能是由于被短时间的利益牵着走,过早压榨掉了价值,若是能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。