深入探索 Android 内存优化(炼狱级别-上)

3、Android 内存管理机制

Android 中的内存是 弹性分配 的,分配值 与 最大值 受具体设备影响

对于 OOM场景 其实可以细分为如下两种:

  • 1)、内存真正不足
  • 2)、可用(被分配的)内存不足

我们需要着重注意一下这两种的区分。

4、小结

以Android中虚拟机的角度来说,我们要清楚 Dalvik 与 ART 区别Dalvik 仅固定一种回收算法,而 ART 回收算法可在 运行期按需选择,并且,ART 具备 内存整理 能力,减少内存空洞

最后,LMK(Low Memory killer) 机制保证了进程资源的合理利用,它的实现原理主要是 根据进程分类和回收收益来综合决定的一套算法集

四、内存抖动

内存频繁分配和回收 导致内存 不稳定,就会出现内存抖动,它通常表现为 频繁GC、内存曲线呈锯齿状

并且,它的危害也很严重,通常会导致 页面卡顿,甚至造成 OOM

1、那么,为什么内存抖动会导致 OOM?

主要原因有如下两点:

  • 1)、频繁创建对象,导致内存不足及碎片(不连续)
  • 2)、不连续的内存片无法被分配,导致OOM

2、内存抖动解决实战

这里我们假设有这样一个场景:点击按钮使用 handler 发送一个空消息,handler 的 handleMessage 接收到消息后创建内存抖动,即在 for 循环创建 100个容量为10万 的 strings 数组并在 30ms 后继续发送空消息。

一般使用 Memory Profiler (表现为 频繁GC、内存曲线呈锯齿状)结合代码排查即可找到内存抖动出现的地方。

通常的技巧就是着重查看 循环或频繁被调用 的地方。

3、内存抖动常见案例

下面列举一些导致内存抖动的常见案例,如下所示:

1、字符串使用加号拼接

  • 1)、使用StringBuilder替代
  • 2)、初始化时设置容量,减少StringBuilder的扩容

2、资源复用

  • 1)、使用 全局缓存池,以 重用频繁申请和释放的对象
  • 2)、注意 结束 使用后,需要 手动释放对象池中的对象

3、减少不合理的对象创建

  • 1)、ondraw、getView 中创建的对象尽量进行复用
  • 2)、避免在循环中不断创建局部变量

4、使用合理的数据结构

使用 SparseArray类族、ArrayMap 来替代 HashMap

五、内存优化体系化搭建

在开始我们今天正式的主题之前,我们先来回归一下内存泄漏的概念与解决技巧。

所谓的内存泄漏就是 内存中存在已经没有用的对象。它的 表现 一般为 内存抖动、可用内存逐渐减少。 它的 危害 即会导致 内存不足、GC频繁、OOM

而对于 内存泄漏的分析 一般可简述为如下 两步

  • 1)、使用 Memory Profiler 初步观察
  • 2)、通过 Memory Analyzer 结合代码确认

1、MAT回顾

MAT查找内存泄漏

对于MAT来说,其常规的查找内存泄漏的方式可以细分为如下三步:

  • 1)、首先,找到当前 Activity,在 Histogram 中选择其 List Objects 中的 with incoming reference(哪些引用引向了我)
  • 2)、然后,选择当前的一个 Path to GC Roots/Merge to GC Roots 的 exclude All 弱软虚引用
  • 3)、最后,找到的泄漏对象在左下角下会有一个小圆圈

此外,在 Android性能优化之内存优化 还有几种进阶的使用方式,这里就不一一赘述了,下面,我们来看看关于 MAT 使用时的一些关键细节。

MAT的关键使用细节

要全面掌握MAT的用法,必须要先了解 隐藏在 MAT 使用中的四大细节,如下所示:

  • 1)、善于使用 Regex 查找对应泄漏类
  • 2)、使用 group by package 查找对应包下的具体类
  • 3)、明白 with outgoing references 和 with incoming references 的区别
  • with outgoing references:它引用了哪些对象
  • with incoming references:哪些对象引用了它
  • 4)、了解 Shallow Heap 和 Retained Heap 的区别
  • Shallow Heap:表示对象自身占用的内存
  • Retained Heap:对象自身占用的内存 + 对象引用的对象所占用的内存

MAT 关键组件回顾

除此之外,MAT 共有 5个关键组件 帮助我们去分析内存方面的问题,分别如下所示:

  • 1)、Dominator_tree
  • 2)、Histogram
  • 3)、thread_overview
  • 4)、Top Consumers
  • 5)、Leak Suspects

下面我们这里再简单地回顾一下它们。

1、Dominator(支配者):

如果从GC Root到达对象A的路径上必须经过对象B,那么B就是A的支配者。

2、Histogram和dominator_tree的区别:
  • 1)、Histogram 显示 Shallow Heap、Retained Heap、Objects,而 dominator_tree 显示的是 Shallow Heap、Retained Heap、Percentage
  • 2)、Histogram 基于 的角度,dominator_tree是基于 实例 的角度。Histogram 不会具体显示每一个泄漏的对象,而dominator_tree会
3、thread_overview

查看 线程数量线程的 Shallow Heap、Retained Heap、Context Class Loader 与 is Daemon

4、Top Consumers

通过 图形 的形式列出 占用内存比较多的对象

在下方的 Biggest Objects 还可以查看其 相对比较详细的信息,例如 Shallow Heap、Retained Heap

5、Leak Suspects

列出有内存泄漏的地方,点击 Details 可以查看其产生内存泄漏的引用链

2、搭建体系化的图片优化 / 监控机制

在介绍图片监控体系的搭建之前,首先我们来回顾下 Android Bitmap 内存分配的变化

Android Bitmap 内存分配的变化

在Android 3.0之前
  • 1)、Bitmap 对象存放在 Java Heap,而像素数据是存放在 Native 内存中的
  • 2)、如果不手动调用 recycle,Bitmap Native 内存的回收完全依赖 finalize 函数回调,但是回调时机是不可控的
Android 3.0 ~ Android 7.0

Bitmap对象像素数据 统一放到 Java Heap 中,即使不调用 recycle,Bitmap 像素数据也会随着对象一起被回收。

但是,Bitmap 全部放在 Java Heap 中的缺点很明显,大致有如下两点:

  • 1)、Bitmap是内存消耗的大户,而 Max Java Heap 一般限制为 256、512MB,Bitmap 过大过多容易导致 OOM
  • 2)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值