美文网首页
内存优化

内存优化

作者: 修塔寻千里 | 来源:发表于2019-08-22 17:48 被阅读0次

一、内存问题

1、很多的异常退出、崩溃和卡顿都是由内存引起的,所以内存相关的优化是开发人员经常要面临和处理的难题。内存主要造成两个问题:

image.png
  • 第一个问题是异常
    异常包括OOM、内存分配失败,因内存不足导致的应用被杀死、设备重启等问题。
  • 第二个问题是卡顿
    Java内存不足会导致频繁的GC,这个问题再Dalvik虚拟机上表现的尤为明显,而ART虚拟机再内存管理上做了大量的优化,内存分配和GC效率大大提高。

2、内存使用方面有两个误区

  • 误区一:内存占用越少越好
    VSS、PSS、Java堆内存不足都可能引发异常和卡顿,从而认为内存使用越少越好。然而应用是否占用了过多内存,没有一个明显的数值界限,而是根据手机的配置和运行环境相关,当内存充足时,使用更多的内存可以获得更好的性能,当内存不足时应当做到“用时分配,及时分配”。
    Android Bitmap内存分配的变化:
  1. 在Android 3.0之前,Bitmap对象放在Java堆,而像素数据放在Native内存中,如果不手动调用recycle,Bitmap Native内存回收完全依赖finalize函数回调,而finalize函数回调的时机十分的不靠谱。
  2. Android 3.0~ Android 7.0将Bitmap对象和像素数据统一放到Java堆中,这样就算我们不调用recycle,Bitmap内存也会随着对象一起回收。然而Bitmap是内存消耗大户,常常会导致Java堆内存不足而OOM。
  3. Android 8.0之后,利用NativeAllocationRegistry机制做到像素数据放在Native内存中,Bitmap对象放在Java堆中,和对象一起快速释放。
  • 误区二:Native内存不用管
    当物理内存不足时,系统开始杀进程,从后台、桌面、服务、前台,直到手机重启,系统安装优先级有条不紊的执行操作。


Fresco图片库在处理图片时就是将图片存储在Native内存中,在Android 5.0~7.0采用的方法如下:
步骤一:通过直接调用libandroid_runtime.so中Bitmap的构造函数得到一张空的Bitmap图片对象,而它的内存是放到Native堆中;
步骤二:通过系统的方式创建一张普通的Java Bitmap;
步骤三:将Java Bitmap的内容绘制到之前申请的空的Native Bitmap中;
步骤四:将申请的Java Bitmap释放,实现图片内存的”偷龙转凤“。

二、测量方法

1、Java内存分配

跟踪Java堆内存的使用情况,常用的工具是Allocation Tracker和MAT。
Allocation Tracker有三个缺点:

  • 获取的信息过于分散,中间夹着这不少其他的信息,很多信息不是应用申请的
  • 无法做到自动化分析,每次都需要手动开始和结束
  • 虽然在跟踪的时候性能消耗很小,但在结束的时候,直到把数据dump出来之前,经常会吧手机完全卡死,甚至ANR。

2、Native内存分配

谷歌建议我们使用Chromium的AddressSanitize,目前其内存泄漏检测支持x86_64 Linux和OS X系统。另外还可以使用Malloc调试和Malloc钩子的方式监测内存问题。Malloc调试可以帮助我们去调试Native内存的一些使用问题,例如堆破坏、内存泄漏、非法地址等。Malloc钩子是在Android P之后,Android的libc支持拦截在恒旭执行期间繁盛的所有分配/释放调用,这样我们可以构建自己的内存检测工具。

三、内存优化方案

1、设备分级

内存优化首先需要根据设备环境来综合考虑。

  • 设备分级
    针对不同的设备采用不同的方案,如在低内存手机降低图片的分辨率和质量
  • 缓存管理
    使用统一的缓存管理方案,当系统内存不足时,能够及时地把内存还回去
  • 进程模型
    一个空的进程也会至少占用10M内存,减少应用进程数、常驻进程,有节制的使用进程
  • 安装包大小
    安装包体积过大,资源文件占用过多,可以适当缩减或退出精简版

2、Bitmap优化

  • 统一图片库
    -统一监控
    大图片监控、重复图片监控、图片总内存监控

3、内存泄漏

内存泄漏主要分两种,一种是同一对象泄漏,另一种更加可怕,每次都会泄漏新的对象。

  • Java内存泄漏,建立类似LeakCanary的自动化检测方案。至少要做到Activity和Fragment的泄漏检测。
  • OOM监控,美团的Probe,在发生OOM时生成Hprof内存快照,然后通过单独的进程对这个文件进一步分析。
  • Native内存泄漏监控
  • 针对无法重变so的情况,使用PLT Hook拦截库的内存分配函数,然后重定向到我们自己的实现后记录分配的内存地址、大小、来源so库路径等信息
  • 针对可重编so情况,通过GCC的“-finstrument-functions"参数给所有函数插桩,桩中模拟调用栈入栈出操作,通过Id的“-wap”参数拦截分配和释放函数,重定向到我们自己的实现后记录分配的内存地址、大小、来源so库路径等信息

4、内存监控

1.采集方式
在前台时,可以间隔时间采集一次PSS、Java 堆、图片总内存。也可对用户进行抽样采集,全天采集。
2、计算指标
内存异常率:可以反映内存占用的异常情况,
内存 UV 异常率 = PSS 超过 400MB 的 UV / 采集 UV
触定律:可以反映Java内存的使用情况,如果超过85%最大堆限制,GC会变得频繁,容易造成OOM
内存 UV 触顶率 = Java 堆占用超过最大堆限制的 85% 的 UV / 采集 UV
3、GC监控
Android 6.0之后系统可以拿到更加精准的GC信息,需要特别注意阻塞式GC凡人次数和耗时,因为它会暂停应用线程,可能导致卡顿和ANR。

相关文章

网友评论

      本文标题:内存优化

      本文链接:https://www.haomeiwen.com/subject/lbjmsctx.html