当前位置: 首页 > news >正文

了解 Android 内存使用情况 - Google I/O 大会演讲

https://www.youtube.com/watch?v=w7K0jio8afM
在这里插入图片描述

在这里插入图片描述

00:07 理查德·乌勒:我
叫理查德·乌勒。
00:09 我是
Android Runtime 团队的一名软件工程师。
00:13 过去三年来,我一直
试图更好地了解
00:16 Android 上的内存使用情况。
00:18 最近,我一直在
与第一方应用程序
00:20 开发人员合作,以
应对评估
00:23 和改进
Android 内存使用方面的挑战。
00:26 很高兴看到
这里有这么多人
00:28 对
Android 内存使用感兴趣。
00:31 首先,
作为应用程序开发人员,您为什么要
00:35 关心内存使用情况?
00:37 对我来说,这实际上与
Android 生态系统有关,即
00:40 应用程序生态系统、设备生态系统
00:44 以及
这些设备的用户生态系统。
00:46 内存的作用
并不
00:49 只限于
00:51 拥有大量
可用内存的高端设备,而
00:53 对于入门级设备来说则更为重要。
00:55 因为这些设备需要
选择合适的低内存
00:59 应用程序才能正常运行。
01:01 如果应用程序内存的使用
和要求增加,
01:05 那么入门级
设备将无法正常工作。
01:07 如果它们不能
很好地工作,OEM 将
01:10 不愿意生产这些设备。
01:12 如果他们不
生产这些设备,
01:13 那么,我们就会将
一批用户排除
01:17 在我们的 Android 生态系统之外。
01:19 这是一件坏事。
01:20 因此,应用程序开发人员
01:23 在开发
应用程序时要尽其所能提高
01:25 内存使用效率,
01:29 减少内存使用,防止内存
增长过多,
01:32 这样我们就可以选择一些
低内存应用程序,
01:35 让入门级设备
表现良好,运行良好。
01:39 如果发生这种情况,OEM
将生产这些设备,
01:43 我们可以将它们交到
用户手中
01:45 以使用我们的应用程序。
01:49 因此,在本次演讲中,我
将讨论三大
01:51 类别、三个领域。
01:53 首先,我将讨论
01:56 Android 设备
01:58 内存不足时会采取的机制,
以及这会对用户产生什么影响。
02:02 我将讨论如何评估
应用程序的内存影响,
02:07 特别是需要注意的一些
非常重要的因素
02:09 。
02:13 第三,我将为
您提供一些有关
02:15 如何减少
应用程序内存
02:17 影响的提示,特别是考虑到
02:21 应用程序中进行的许多分配都源自
02:25 其运行的 Android 堆栈深处。
02:30 我们开始吧。
02:31 当设备内存不足时会发生什么

02:36 嗯,设备上的内存,
设备上的物理内存,
02:39 被组织或
分组为页面。
02:42 每页通常
约为四千字节。
02:46 不同的页面可
用于不同的用途。
02:48 因此页面就可以用作页面。
02:52 这些是
正在
02:53 被进程主动使用的页面。
02:55 它们可以是缓存页面。
02:57 这些是正在被
进程使用的内存页面,
03:00 但它们包含的数据也
位于设备存储的某个位置
03:05 ,这意味着我们
有时可以回收这些页面。
03:09 然后,设备上
可能还有
03:10 您未使用的空闲内存页面。
03:14 所以我所做的就是
拿一个两千兆字节的设备,
03:18 然后启动它,什么也不做。
03:20 因此在
时间刚开始的时候,
03:21 运行时并没有运行。
03:23 然后我开始
越来越多地使用它。
03:26 因此,许多不同的
应用程序都在运行,
03:32 随着时间的推移,设备上的内存使用量会越来越大。
03:34 因此,我们可以在开始时看到,在我开始运行之前,
那里有一条平坦的线
03:38 。
03:40 然后我启动运行时。
03:42 设备上有大量可用内存。
03:45 这是一个令人高兴的设备,
因为如果应用程序需要
03:48 更多内存,内核可以
立即
03:52 从可用内存中满足该请求。 随着
03:55 时间的推移,当您
使用更多的内存时,
03:58 可用内存就会耗尽。
04:00 它下降了。
04:01 为了避免发生非常糟糕的
事情,
04:04 Linux 内核
启动了一个
04:06 称为 kswapd 的机制。
04:09 而kswapd的工作就是
寻找更多的空闲内存。
04:13 当可用
内存
04:16 低于我在
这里所说的 kswapd 阈值时,就会启动此功能。
04:19 kswapd
04:22 用来寻找更多可用内存的主要机制
是回收缓存的页面。
04:29 现在,如果应用程序
访问缓存页面,
04:33 或者缓存页面上的内存
已被回收,
04:36 则需要花费
一些额外的时间
04:39 从设备存储中重新加载该数据。
04:41 但用户可能
不会注意到这一点。
04:43 那就没问题了。
04:46 现在,我使用越来越
多的应用程序,
04:50 它们使用更多的内存。 随着 kswapd 开始回收缓存页面,
04:52 缓存页面的数量
将会下降
04:55 。
04:56 如果缓存太低,
缓存的页面太少,
04:59 设备就会
开始崩溃。
05:02 这是非常糟糕的事情,
因为基本上设备
05:05 将完全锁定。
05:06 因此在 Android 上,我们
有一个
05:08 称为
低内存杀手的机制,
05:11 当
缓存内存量过低时,该机制就会启动。
05:15 它的工作方式
是低内存杀手
05:17 会
在设备上选择一个进程,
05:20 并将其杀死。
05:21 它将恢复
05:23 该进程使用的所有内存。
05:26 现在,这是一种
令人不快的状态,
05:30 特别是当低内存
杀手杀死
05:33 用户关心的进程时。
05:36 因此,让我进一步向
您介绍一下
05:40 低内存
杀手如何决定杀死什么。
05:43 Android 会跟踪
05:46 设备上运行的进程。
05:48 并且它使它们保持
优先顺序。
05:50 因此优先级最高的
进程是本机进程。
05:54 这些是
Linux 自带的,
05:56 比如我之前提到的 init、kswapd,还有
05:59 像 netd、logd 这样的进程。
06:02 而 Android 特有的
特定守护程序,adbd、
06:05 installd——基本上任何
正在运行的本机进程都
06:08 归入这一类。 我们拥有的
06:11 下一个最高
优先级进程
06:13 是系统服务器,
它维护此列表,
06:18 其次是所谓的
持久进程。
06:21 这些都是
核心功能,
06:23 所以 [听不清],NFC、SMS 之
类的东西。
06:29 接下来,我们有
前台应用程序。
06:31 因此这将是
用户
06:33 直接交互的应用程序。
06:35 在这种情况下,
用户可能正在查看网页,
06:38 因此他们正在
与 Chrome 应用进行交互。
06:41 接下来优先考虑的是
所谓的可感知或可见的
06:45 过程。
06:46 这些不是
用户直接
06:49 交互的过程,但可以
以某种方式感知。
06:52 例如,如果您
有一个搜索过程,
06:54 也许
屏幕上会有一点 UI。
06:58 或者如果用户正在
后台听音乐,
07:00 那么他们可以
通过耳机听到音乐。
07:02 他们能够感知到它。
07:05 在可感知的
应用程序之后,我们有了服务。
07:07 这些是
由应用程序启动的服务,用于
07:10 诸如下载、上传、
从云端下载之类的操作。
07:16 然后我们有了 Home 应用程序。
07:17 这是您
按下“主页”按钮时所得到的结果。 如果您有壁纸的话,
07:19 它通常会托管您的壁纸

07:23 因此,除了这些
正在运行的进程之外,
07:25 我们还会跟踪
07:28 用户之前使用的应用程序。
07:29 因此,也许他们正在使用
这个红色应用程序,即您的红色应用程序,
07:33 并
通过链接将他们带到 Chrome。
07:36 然后,当他们
切换到 Chrome 时,
07:38 该应用程序将
成为之前的应用程序。
07:41 我们还在内存中保留了
一堆其他进程,
07:46 它们是
用户以前使用过的缓存应用程序。
07:51 有些可能是
最近才出现的,有些则可能
07:52 要过一段时间才出现。
07:55 我想在这里指出的
是,这些缓存进程——
07:58 当我使用术语“缓存”时,
这与
08:00 我之前谈到的缓存内存页面的用法不同
08:03 。
08:06 好的,我们保留
以前和缓存的进程的原因
08:10 是,如果
用户想要切换
08:12 到其中一个
应用程序,并且说,
08:14 他们想切换到
以前应用程序,
08:17 那么
切换到那个应用程序非常快。
08:19 我应该说这是针对
处于正常内存
08:23 状态的设备。
08:24 因此,如果您想切换
到以前的应用程序,
08:26 那会非常快。
08:28 但是,如果您想
切换到恰好
08:30 处于
缓存进程中的应用程序,那么
08:32 这可以非常快地完成,
因为它已经在内存中。 但是,
08:36 如果我们退一步
思考,那么,
08:39 当设备内存不足时会发生什么

08:42 在这种情况下,我们可以想象正在
运行的应用程序所使用的内存
08:47 正在增长。
08:48 缓存页面的数量
降至低内存杀手
08:52 阈值以下。
08:52 低内存杀手现在
必须介入并杀死某些东西
08:57 以释放一些内存。
08:58 好吧,它将
08:59 从这个列表的底部开始杀戮。
09:01 所以也许它会杀死
这个蓝色的应用程序。
09:05 那已经消失了。
09:06 我们
为仍在运行的应用程序恢复了更多的内存
09:09 。
09:10 但是如果用户
现在想要切换
09:12 并开始使用该
蓝色应用程序,
09:14 它就不会再被缓存。
09:16 这意味着
启动
09:21 该应用程序将需要很长时间。
09:21 可能需要
两三秒钟,
09:23 也许它已经失去了一些状态。
09:25 因此,这是用户第一次
真正开始感觉到,哦,
09:29 这里发生了一些事情,
导致速度变慢。
09:34 如果
正在运行的进程
09:35 继续使用更多内存,
那么我们就会面临更大的内存
09:39 压力,低内存
杀手将
09:41 开始杀死更多
缓存进程。
09:44 如果它们继续增长
,直到最终
09:48 只剩下几个缓存进程,此时,
09:51 我们认为设备内存
状态至关重要。
09:54 这是一个非常糟糕的地方。 但是,
09:56 如果正在运行的进程
继续使用更多内存
09:59 ,低内存
终止程序将
10:01 不得不终止更多进程。
10:03 最终,它将
毁掉整张地图。
10:06 此时,用户
会问,嘿,
10:09 我的壁纸怎么了?
10:10 因为当他们
回到家时,
10:12 屏幕会黑
几秒钟,
10:14 然后壁纸才会
再次启动。
10:16 如果情况更糟,也许
一个可察觉的过程
10:20 正在杀死你。
10:20 用户会说,嘿,
我的音乐怎么了?
10:23 我正在听,然后
它就停了。
10:27 非常糟糕的情况是,
前台应用程序被终止,
10:30 用户看起来就像
应用程序崩溃了一样。
10:34 对于
低内存杀手来说,最极端的情况
10:36 是它需要
杀死系统服务器。
10:40 看起来您的
手机已重启。
10:42 因此,这些都是设备内存不足时产生的
非常明显的影响
10:46 。 当您的设备出现这种情况时,
10:49 这不是一个好的
用户体验
10:51 。
10:55 我想回到
之前展示的这个图表,了解
11:02 当您使用更多内存时设备上的内存页面会发生什么情况。
11:04 这是一个两千兆字节的设备。
11:06 您认为
这张图是什么样子的,4 兆字节
11:10 还是 512 兆字节的设备?
11:12 我将给你几
秒钟的时间来思考这个问题。
11:26 您知道
它是什么样子的吗?
11:28 因此我尝试在
512 兆字节的设备上进行此操作。
11:31 同样的事情,启动
运行时,使用更多的内存,
11:34 它看起来
像这样。
11:36 因此,由于一开始可用的
内存非常少
11:38 ,在 kswapd 启动之前,
11:40 我们可以使用的空闲页面非常少
11:44 。
11:45 然后在需要
11:47 低内存杀手
11:49 开始终止程序之前,我们可以回收的缓存页面也非常少。
11:51 因此,你可以想象,
如果你有这个设备,
11:54 并且低内存
杀手始终处于活动状态,
11:55 它总是终止进程,
并导致这种糟糕的用户
12:01 体验,那么
OEM 可能不会
12:04 太有兴趣
运送这个设备,因为
12:07 它不能很好地工作。
12:08 这又回到了
12:12 我在一开始提到的生态系统挑战。
12:14 这就是我们
关心记忆的原因。
12:22 现在,我们如何知道
应用程序使用了多少内存
12:25 ? 事实上,
12:26 我们如何知道您的
应用程序的内存?
12:31 我告诉过你,设备上的内存被
分成多个页面。
12:35 Linux 内核
将跟踪设备
12:37 上运行的每个进程
正在使用的页面。
12:41 因此,也许我们有一个系统
进程、Google Play 服务
12:44 进程和几个
在设备上运行的应用程序。
12:47 我们想知道它们各自对
记忆的影响。
12:50 好吧,只需计算一下
它使用的页数。
12:57 由于共享的原因,情况会比这稍微复杂一些,
因为
13:01 设备上的多个进程可以
共享内存。
13:03 例如,如果
您有一个应用程序正在
13:05 调用 Google
Play 服务,
13:08 它将与 Google Play 服务进程共享一些
内存,可能是代码内存
13:11 或其他类型的内存
13:13 。
13:14 然后我们可以
问,我们应该如何
13:17 解释这个共享内存?
13:19 这是
13:21 应用程序的责任的一部分吗?
13:22 我们应该关心记忆影响吗? 您可以通过
13:26 几种不同的
方法来解决这个问题。
13:30 一种是使用我们所说的
驻留集大小,或RSS。
13:34 这意味着,当
我们计算应用程序、RSS 时,
13:37 应用程序要对
13:42 与其他应用程序共享的所有内存页面负全部责任。
13:45 另一种方法称为
比例集大小 (PSS)。
13:49 在这种情况下,
我们会说
13:51 应用程序负责
这些共享
13:53 页面,其数量与共享这些页面的
进程数量成正比
13:56 。
13:57 因此在这种情况下,两个
应用程序或进程
14:00 共享这些页面。
14:02 我们可以这么说,应用程序占了
其中一半的份额。
14:05 如果有三个进程
共享相同的内存,
14:08 我们会说该应用程序
负责
14:10 其中的三分之一,依此类推。
14:13 然后,
您可以采取的第三种方法
14:15 称为唯一
集合大小,我们
14:17 说应用程序
不对其任何
14:20 共享页面负责。
14:23 现在,一般来说,
采取哪种方法确实
14:26 取决于具体情况。
14:28 举例来说,如果这些
共享页面
14:32 在
14:34 您的应用调用 Google Play 服务之前未在
Google Play 服务应用中使用,那么
14:39 说
该应用负责所有
14:42 这些页面也许是有意义的。
14:43 我们想使用 RSS。
14:45 另一方面,
如果这些页面
14:48 在
14:51 应用程序调用 Google Play 服务之前位于
Google Play 服务进程的内存中,
14:55 它们一直在
那里,应用程序没有将
14:57 它们带入内存,那么
我们就不会想计算它们。
14:59 USS 更合适。
15:02 一般来说,
15:06 至少在系统
层面,我们无法了解这个高级上下文,所以我们采取的方法
15:09 是最直接的
方法,即按比例设置
15:12 大小并平等共享。
15:14 使用 PSS
评估应用程序的
15:18 内存影响的一个好处是,尤其是在同时
查看多个进程时
15:22 ,
它可以避免共享页面的
15:24 计数过多或过少

15:30 因此,请使用 PSS 来降低
应用程序的内存影响。
15:35 您可以运行此命令,
adb shell dumpsys meminfo -s。
15:41 为其指定您的进程名称,
com 点示例、点 Richard
15:46 或任何其他名称,或者
15:48 如果您碰巧知道的话,您可以指定进程 ID。
15:49 它将
输出
15:51 类似这样的内容,即应用程序内存的应用程序摘要视图

15:55 最底部
是总数。
15:57 这个数字就是
应用程序的 PSS。
16:01 这是 adb shell
dumpsys meminfo -s。
16:07 现在,假设你这样做。
16:09 您弄清楚了
您的应用程序的 PSS 是什么。
16:12 有一个非常有趣的
问题。
16:15 您的应用程序应该使用多少内存?
16:19 因为——我之前说过,
如果我们使用大量内存,
16:22 那就不好了,因为低
内存杀手会启动。
16:25 但我们使用
内存实际上是有原因的。
16:28 我们利用它来
提供功能、
16:30 提供用户价值、
提供愉悦感。
16:33 让我们的应用程序变得出色的一切
16:35 都会占用内存。
16:37 因此我们在
用户价值和内存之间进行权衡。
16:43 这就是我在
这张图中展示的权衡空间。
16:46 在理想情况下,我们
位于
16:49 图表的左上方,在那里我们
提供了大量的用户价值,而对
16:53 内存几乎没有影响。
16:56 但在实践中,这在
16:58 技术上可能是不可行的,
因为你需要内存来
17:03 提供价值。
17:05 而有限的内存
所能提供的价值也是有限的
17:06 。
17:10 另一方面,
另一个极端
17:12 是,您
使用了大量内存却
17:16 没有提供太多价值。
17:18 我认为可以肯定地
说这不是
17:20 一个很好的应用程序,因为
它基本上提供了
17:23 太多的内存,
使用了太多的内存。
17:27 不幸的是,我的幻灯片
显示不正确。
17:30 但是想象一下
17:35 这个应用程序占用的内存过多的曲线。
17:37 对于用户来说,它不值得使用。
17:40 啊,他们走了。
17:41 精彩的。
17:43 接下来,我们可以看看
图表的这个角落,
17:47 我们没有提供
太多的用户价值。
17:49 我们没有使用太多内存。
17:51 我们可以说这是一个
小应用程序,也许是
17:54 您的桌面时钟应用程序。
17:57 另一方面,我们可以让
17:58 应用程序使用大量内存
来提供大量价值。
18:02 这些都是大型应用程序,
可能是照片编辑器,
18:05 或类似的东西。
18:07 我们可以说,
那么,还有什么更好的呢?
18:08 小型应用程序还是大型应用程序?
18:10 在这种情况下,它们都很
有用,
18:15 只是当我说
某个应用程序使用了
18:18 太多内存时,这实际上
取决于你在什么类型的设备
18:22 上运行。
18:23 如果您在
高级设备上运行,
18:25 它可以支持
更大的应用程序。
18:27 但是在较小的设备、
入门级设备上,
18:30 这个大型应用程序可能会
使用太多内存,
18:32 这不合理。
18:34 所以实际上我应该
划一条线
18:36 并说,太多的内存
取决于设备。
18:38 高级、中级
和入门级
18:43 可能不支持
大型应用程序。
18:47 不管是好是坏,
我经常看到的情况
18:51 是,随着时间的推移,当您
开发应用程序时,
18:54 您往往会添加更多功能。
18:57 它往往会占用更多内存。
18:59 因此,您倾向于
在这张图中向上和向右移动。
19:03 现在,这实际上
对中端和高端用户来说是件好事,
19:07 因为他们可以获得
更高的价值,在
19:09 内存方面也更加物有所值,但在这种情况下,
19:12 对于入门级设备用户来说,这有点不幸,
19:15 因为虽然他可以使用
旧版本的应用程序,但
19:18 您现在添加了
如此多的功能,
19:19 并且占用了如此多的
内存,以至于它
19:22 在他们的设备上运行得不那么好。
19:25 所以
我想在这里说的要点
19:27 是,
任何可以
19:29 提高应用程序
内存效率的方法都是好的。
19:32 因此,如果您可以
在此图表上向左移动,
19:35 那么就可以减少内存使用量,而不会
牺牲用户价值,
19:38 那就太好了。
19:40 并且请注意,
当您
19:41 添加新功能时,虽然
它可能对中端
19:46 和高端设备用户有利,但
可能会对
19:49 这些入门级设备产生负面影响。
19:53 这张图有问题。
19:58 有人知道它是什么吗?
20:00 嗯,让我看看。
20:02 该图的问题在于,它
20:04 表明应用程序的
内存使用量是一个数字。
20:08 所以你给我这个申请,
我可以告诉你它的 PSS。
20:12 但实际上,
情况并非如此,
20:15 因为应用程序的
内存影响
20:17 取决于许多
不同的因素,
20:20 例如应用程序
用例、平台
20:23 配置和
设备内存压力。
20:27 因此,
当您测试应用
20:30 程序的
内存时,注意这一点很重要,也许测试
20:33 回归,或者查看
优化是否有效,
20:37 以确保您正在
测试您关心的应用程序用例,
20:40 并且您正在
控制
20:42 所有其他
参数,以便您
20:45 进行适当的苹果
与苹果的比较。
20:49 让我
更详细地讲一下。
20:51 那么应用程序
用例如何影响内存?
20:56 我在这里所做的是
开始使用 Gmail。 随着时间的推移,
20:59 我已经在应用程序中切换到
不同的用例
21:01 。
21:03 所以每 20 秒我就会切换一次。
21:05 我首先查看了
收件箱,发现 PSS 仅使用了
21:08 100 多兆字节。
21:10 然后我转而查看
包含一些文本的电子邮件,
21:13 使用了更多的内存。
21:15 我转而查看
另一封电子邮件,
21:17 这次带有图片。
21:19 它使用更多内存。
21:20 然后我开始撰写
电子邮件,用得少一点。
21:23 我停止使用该应用程序,
然后它占用的内存就少了。
21:27 因此您可以看到,
根据应用程序的
21:30 使用情况,内存影响
差异很大。
21:35 并且,将
21:37 应用程序的
内存从
21:40 A 点与 B 点进行比较并不一定有意义,因为它们
是不同的用例。
21:47 应用程序用例是一个
非常简单的因素。
21:50 不太
明显的是,您的内存
21:54 将
根据
21:56 平台配置发生很大变化。
21:58 因此,我
在这张图表中展示的
22:00 是,我从上一张幻灯片中选择了一个
应用程序
22:03 用例
,Gmail,查看
22:06 一封带有图片的电子邮件。
22:09 我已经在很多
不同的设备上运行过它。
22:11 因此,Nexus 4、Nexus 5X、
Nexus XP、Pixel XL,甚至在同一设备中,也
22:16 存在多个不同的
平台版本
22:19 。
22:20 举例来说,
对于 Nexus 5,
22:23 我在 Android
M、N 和 O 上运行它。您
22:27 可以看到,
22:31 此应用程序用
例占用的内存量存在很大差异。
22:35 出现这种情况的原因是,
对于不同的设备,
22:38 我们有不同的屏幕
分辨率、不同的屏幕
22:40 尺寸,这意味着位图
占用不同数量的内存。
22:46 您可能
22:48 在不同的设备上有不同的平台优化。
22:50 您可能有不同的
zygote 配置、
22:53 不同的运行时
配置,以
22:55 不同的方式运行您的代码。 这里
22:57 有很多
不同的因素
23:00 ,当您
切换到不同的平台
23:03 配置时,您将
获得不同的内存使用情况。
23:08 所以我想说,当你
测试应用程序的
23:10 内存使用情况时,尽量
23:13 使用一致的平台
设置、相同类型的设备、
23:17 相同的平台版本
以及相同的
23:20 设备运行场景。
23:26 现在
我想谈谈第三种情况,
23:28 这种情况非常有趣,
因为它有点
23:30 违反直觉,
即应用程序的内存
23:33 影响取决于
设备的内存压力。
23:38 所以在这里,我所做的是,
我采用了 Chrome 应用程序,
23:41 并开始在
23:44 具有大量可用内存的设备上运行它。
23:46 然后我在后台设置
一些本机进程,
23:48 这些进程将慢慢
23:50 占用
设备上越来越多的内存,
23:52 这样我就可以看到
当设备处于
23:55 中等内存压力
或高内存压力下时 Chrome 会发生什么。
23:59 我们可以看到,

24:00 设备上有足够的可用内存时,
内存压力较低,Chrome 的
24:04 PSS 除了出现
小幅峰值外,其他方面都相当平稳,这
24:07 可能是
应用程序用
24:10 例 [听不清] 平台的一些变化。
24:13 当设备承受
足够的内存压力时,
24:16 kswapd 就会启动并开始
回收缓存的页面,
24:20 而
它回收的一些页面
24:22 将来自
Chrome 进程。
24:25 这会
导致 Chrome 的内存
24:27 影响下降。
24:28 它的 PSS 将会
下降,直到最终,
24:32 如果设备的
内存压力太大,
24:34 低内存杀手
就会被激活,并决定要
24:37 杀死 Chrome,
那么 Chrome 的 PSS
24:40 将会
很快降至零。
24:44 所以您可以看到,
即使对于相同的应用程序
24:47 用例、相同的
平台配置,
24:50 我们也
可能会获得各种各样的 PSS 值。
24:54 所以你必须要
小心一点。
24:57 想象一下我已经想出了这个
Chrome APK 的优化版本
25:00 。
25:01 它有这种
浅蓝线,表示内存
25:04 配置文件。
25:05 我相信从内存角度来看这
是一个优化版本
25:09 的 APK,
25:11 因为对于每个级别的
设备内存压力,
25:14 它都会使用更少的内存。
25:16 但是如果我正在进行
测试,并且
25:18 在 A 点对原始 Chrome 版本的 PSS 进行采样,
25:22 但是我在 B 点对
据称已优化的 Chrome
25:27 版本的 PSS 进行采样
并进行比较,
25:29 然后我说,哦,好吧,A
小于 B,因此 A 占用的内存较少,
25:34 我可能会错误地得出结论,
原始版本的 Chrome
25:38 比我的
优化版本更好。
25:41 因此,
在比较 PSS 值时必须非常小心,
25:44 以确保设备
内存压力相同。
25:47 否则,您可能会得到
这些有趣的结果。
25:51 我的建议是,由于
25:54 设备
内存压力很难控制,因此请在具有大量可用 RAM 的
25:56 设备上运行测试,
26:01 这样
设备内存压力就会较低,
26:03 并且您会发现 PSS
数字
26:06 在该区域会更加稳定。
26:11 因此,我们讨论了为什么您
希望您的应用程序不要
26:16 占用太多
内存,以及
26:18 如何评估您的
应用程序的内存影响。
26:22 现在让我给你
一些关于如何
26:23 减少
应用程序内存影响的提示。
26:26 第一个提示是,
检查 Android Studio 的内存
26:30 分析器。
26:31 分析
应用程序的 Java 堆。
26:34 这将为您提供有关堆上的 Java 对象的
大量有用信息
26:38 。
26:40 因此,它们被分配到哪里、由
什么占用、
26:43 它们有多大,
几乎所有
26:46 您想了解的有关 Java
堆的信息,您都可以从中看到。
26:50 我给你的建议是
关注应用程序堆。
26:53 因此,如果您
在 Android Studio 中打开它,
26:55 您将看到三个堆。
26:56 一个是 zygote 堆,一个是
图像堆,一个是应用程序堆。
27:02 当您的应用程序首次
27:05 启动时,图像和 Zygote 堆将从系统继承。
27:05 所以
你对此无能为力。
27:08 但毫无疑问,你可以
在应用程序堆上做很多事情。
27:13 我不会
详细地讲解
27:16 如何使用这个工具 — —
27:17 或者实际上根本不会讲太多
,因为 Esteban
27:21 将于
明天 12:30 就
27:25 如何使用这个工具进行演讲。
27:27 他的团队开发了这个工具。
27:28 他将讨论
如何进行实时分配
27:31 跟踪和堆分析。
27:33 所以我强烈建议你
明天 12:30 去听一下那个演讲
27:37 。
27:42 所以你说,理查德,
你告诉我们
27:45 我们应该关心 PSS。
27:47 这就是我们的应用程序的
内存影响。
27:50 您刚才告诉我们,我们应该使用
Android Studio 的内存配置文件
27:52 来分析
Java 堆。
27:55 但如果我们看一下这里,我们会
发现,Java 堆
27:58 实际上并不是
28:02 应用程序整体内存影响的很大一部分。
28:04 那么
其余的记忆又如何呢?
28:06 我们在这里应该做什么?
28:09 这很棘手,因为
大多数这些应用程序
28:13 或分配都
28:16 源自平台
堆栈深处,即 Android 堆栈。
28:20 因此,如果您想
了解它们
28:23 并真正理解
它们,那么
28:25 了解更多有关
框架如何实现
28:30 视图系统和资源,
或者本机库
28:34 字体和 SQL 灯、Web 视图如何
工作,从 Android
28:39 运行时,它如何
运行您的代码,
28:42 从硬件抽象
层,图形如何工作,
28:46 一直到
Linux 内核中的虚拟内存管理,都会有所帮助
28:50 。
28:51 顺便说一下,我住在
中间的橙色块中,即
28:54 Android 运行时。
28:56 这就是我在堆栈中的位置。
28:59 所以你可能会问,
好的,那么这个内存
29:01 是来自平台,
还是在平台内部。
29:04 我们应该使用平台
工具来诊断这个内存吗?
29:09 例如,如果 dumpsys meminfo
-s,该摘要视图
29:14 不够,您可以尝试使用
-a 运行 dumpsys meminfo,以
29:18 显示
29:20 从平台角度可以看到的
29:22 有关应用程序
内存使用情况的所有内容。
29:24 这将为您提供
更详细的细分。
29:27 例如,您不会看到
代码内存倒退,而是
29:32 可以看到,是不是因为我的
点 SO 内存映射
29:36 倒退了,还是我的 .APK 或
[INAUDIBLE] 内存映射
29:41 倒退了?
29:43 它还会向您显示
29:45 不同
类别内存的细目分类,
29:47 例如私有内存、干净内存、
共享内存、脏内存等等。
29:51 私有脏内存
就像
29:53 我
在一开始谈到的已使用内存。
29:55 私人清洁内存,
清洁,表明
29:58 它就像
也存在于此的缓存内存。
30:02 因此您可以使用
dumpsys meminfo。
30:04 如果这还不够
详细,也许你会看到,好的,
30:07 .APK mmap 退化了。
30:09 您可以
30:11 在
应用程序上运行一个名为 show map 的工具,它将为
30:13 您提供
30:15 内存映射的更细粒度的细分,
并且它实际上会为
30:20 您提供
30:24 应用程序中正在进行内存映射的特定文件。
30:25 这可以帮助
查明哪些文件
30:29 可能导致了回归。
30:33 在该平台中,我们
有一个我开发的堆转储查看器
30:36 ,名为 [INAUDIBLE] 的
实验性堆
30:39 转储查看器,

30:41 试图显示更多
特定于平台的内容。
30:43 您可以尝试使用它来
了解有关 Java
30:46 堆的更多信息,尽管 Android
Studio 的内存配置文件将
30:49 包含所有相同的信息。
30:53 然后我们的平台上还有
一种
30:55 叫做调试恶意软件的东西。
30:56 您可以在此处对
您的应用程序进行检测,
30:59 以便
它所生成的每个本机应用程序都
31:02 将堆栈
跟踪保存到该分配中。 当您的应用程序运行检测时,
31:06 您可以获取我们所说的
应用程序的本机堆快照,
31:11 如果您有符号,
31:14 则可以对堆栈跟踪进行反符号化

31:16 并且可以获取
所有
31:20 本机分配的本机堆栈跟踪。
31:22 这在运行时有相当大的
开销,
31:25 因此工作起来可能有点
棘手,
31:28 但它提供了
对本机堆的很多洞察。
31:31 所以我们有这些平台工具。
31:33 我们应该使用它们吗?
31:34 我们可以使用它们吗?
31:36 嗯,当然可以。
31:37 它们都是可用的。
31:39 但这些工具也有一些需要注意的地方

31:41 他们往往
得不到很好的支持。
31:44 它们的
用户界面非常笨拙,
31:46 正如您
从我的快照中看到的那样。
31:51 这种方法需要相当
多的深厚平台专业知识才能
31:54 理解,例如,
31:56 Dex mmap、
VDex mmap、[INAUDIBLE] mmap 之间的区别是什么。
32:01 例如,这些东西来自哪里?
32:06 您可能
需要一个路由设备,
32:07 例如在
显示地图和调试恶意软件的情况下。
32:12 如果您想
获得 [INAUDIBLE] 或
32:14 调试 [INAUDIBLE]
需要去符号化的符号,您可能必须自己构建一个平台。
32:17 由于您是
32:20 在页面级别查看内存,因此这些数字往往非常嘈杂。 无论如何,
32:23 您
从这些工具中看到的很多内存都是
32:26 超出
您控制范围的。
32:29 因此,您可能会看到
32:31 与您的代码无关的 zygote 分配、运行时分配。
32:35 所以我不认为尝试使用这些工具
是对时间的最佳利用
32:39 。
32:40 但无论如何,请
继续尝试一下。
32:44 我要给出一个
不同的建议,
32:46 如果你想提高
你的整体内存使用率,
32:50 请做两件事。
32:52 首先,
32:55 像我之前展示的那样,使用 Android Studio 的内存分析器分析你的 Java 堆。
32:57 第二,减少 APK 的大小。
33:00 让我来告诉你为什么。
33:02 我认为这是一种
合理的方法,
33:05 可以减少您的
整体内存影响。
33:09 首先,
Java 堆之外的分配,
33:14 其中许多都
与 Java 分配相关。
33:17 因此,您的应用程序正在
调用 Android 框架,
33:20 而 Android 框架又在幕后
调用本机库
33:22 ,执行
本机分配甚至
33:26 图形分配,
其生命周期
33:28 与 Java 对象相关。
33:32 例如,仅
给您一个示例,
33:35 在 Java 中,在您的
Java 堆上,如果您
33:37 看到这些类型的对象,那么
SQLite 数据库、Web 视图、
33:40 模式,它们都有与之关联的
本机分配
33:43 。
33:45 如果您看到一个 DexFile 对象,
它将具有与之关联的 .Dexmmap、
33:48 .VDex、[INAUDIBLE] mmap

33:51 如果您
的 Java 堆上有线程实例,那么
33:54 它将
与堆栈内存相关联。
33:57 如果您使用位图
或有时使用表面视图
33:59 或纹理视图,则可能会
导致图形内存的使用。
34:03 还有很多其他的。
34:05 因此,如果您专注
于 Java 堆,
34:10 您会担心它
不会在
34:12 其他任何地方提供帮助,但事实并非如此。 Java 堆上
34:14 的优化也
34:16 将有助于其他
内存类别。
34:21 作为我工作的一部分,我正在尝试
更好地揭示
34:24 有关这些
非 Java 堆分配的信息。
34:29 你开始看到这一点。
34:30 如果你查看 Android
Studio 的内存分析器,
34:34 它会报告一个
名为 native 的数字。
34:37 我只是
想让你知道,这
34:39 是对
34:43 可能与 Java
34:46 对象相关的一些非 Java 内存的近似值或建议。
34:47 对此持
保留态度,
34:49 但它
对于揭示
34:52 位图等内存影响确实很有效。
34:58 我的第二个建议是
减少你的 APK 大小。
35:01 你为什么这么做?
35:02 因为很多
占用 APK 空间的东西
35:05 在运行时也会占用内存空间。
35:08 例如,您的
classes.dex 文件
35:11 将以类对象的形式占用
Java 堆上的空间
35:14 。
35:15 它将占用一个
用于内存映射 DexFile 的代码内存。
35:19 它还将
占用
35:21 应用程序
摘要视图运行时元数据中显示的其他私人内容。
35:26 您的
字段、方法和字符串
35:29 等的表示。
35:31 如果您
的 APK 中有位图,则
35:33 在运行时加载这些位图时
,像素数据
35:36 将占用空间,
具体取决于平台
35:38 版本或
您如何加载它们(
35:40 在 Java 堆、
本机堆或作为图形)。
35:45 APK 中的资源
占用 Java 堆上的空间,
35:48 因此您有一个资产
管理器对象。
35:51 此外,在本机堆上,
您有一个显示在那里的已解析的 zip 文件
35:54 结构。
35:56 您将拥有
用于 APK 的代码内存。
36:00 如果您随应用程序
运送库、
36:05 J 和 I 本机库,则 .so 文件
36:08 在运行时访问这些库时
36:10 会占用空间。
36:12 因此,
如果您可以缩小所有这些东西,
36:14 您就可以减少 APK 的大小,也可以
减少内存的大小。
36:17 我会告诉你,可靠地
测量 APK 大小
36:20 比测量内存要容易得多
,因为对于 APK 来说,
36:24 你实际上有
一个表示大小的数字。
36:27 如果您
反复测量单个 APK 的大小,
36:31 您将得到相同的结果,这与
内存非常不同。
36:38 去年在 Google I/O 大会上有一场演讲,
36:40 题为“
缩小应用程序大小的最佳实践”。
36:43 我建议你检查一下。
36:44 这会给你更多的
建议,更具体的行动
36:48 项目,让你能够采取这些措施来
减少这些问题。
36:54 让我快速回顾一下
我们为什么关心内存,以及
36:57 我建议您做些什么来改善
应用程序的内存使用情况。
37:01 首先,我讨论了当
我们在设备上使用更多内存时,
37:05 低内存杀手
最终会启动。
37:08 它会杀死进程。
37:09 如果用户关心
这些过程,那就糟糕了。
37:14 如果设备
运行过多的低内存杀手
37:18 ,那么 OEM 将不愿意
生产入门级
37:23 设备。
37:23 然后我们就失去了这些设备。
37:25 我们失去了这些用户。
37:29 要评估应用程序的
内存影响,请使用 PSS。
37:34 任何可以提高
记忆效率的事情都是好的。
37:39 当您测试内存
回归或优化时,
37:43 请确保您针对的是
37:45 控制平台
37:47 配置时所关心的应用程序用例。 在具有大量可用 RAM 的
37:50 设备上进行测试,
37:52 以帮助控制
设备内存压力。
37:55 为了减少
应用程序的内存使用,
37:59 请尝试 Android
Studio 的内存分析器,
38:02 关注应用程序堆,
参加
38:05 Esteban 明天
12:30 举办的会议,了解
38:08 有关如何执行此操作的更多信息。
38:11 尽你所能
减少你的 APK 大小,
38:14 并查看去年的讨论以了解
如何做到这一点。
38:19 感谢大家的到来。
38:21 我很乐意与
您进一步交流并了解
38:25 您所面临的记忆挑战。
38:28 所以你会发现我,舞台结束后我会在外面
闲逛一会儿
38:30 ,你也可以
38:34 在
Android Runtime
38:36 办公时间找到我,那是 5:30,也
就是
38:40 这次演讲后的几个小时。
38:42 非常感谢。


文章转载自:
http://blackhearted.zzyjnl.cn
http://afterwit.zzyjnl.cn
http://bangka.zzyjnl.cn
http://amperometer.zzyjnl.cn
http://almoner.zzyjnl.cn
http://cancha.zzyjnl.cn
http://bre.zzyjnl.cn
http://choliamb.zzyjnl.cn
http://catenulate.zzyjnl.cn
http://apartment.zzyjnl.cn
http://burghley.zzyjnl.cn
http://chenar.zzyjnl.cn
http://caprificator.zzyjnl.cn
http://carious.zzyjnl.cn
http://abend.zzyjnl.cn
http://acrogenous.zzyjnl.cn
http://bacchii.zzyjnl.cn
http://behave.zzyjnl.cn
http://auriform.zzyjnl.cn
http://armalcolite.zzyjnl.cn
http://avitaminosis.zzyjnl.cn
http://choush.zzyjnl.cn
http://campership.zzyjnl.cn
http://braless.zzyjnl.cn
http://bijection.zzyjnl.cn
http://architect.zzyjnl.cn
http://carthaginian.zzyjnl.cn
http://aerugo.zzyjnl.cn
http://abnegation.zzyjnl.cn
http://carcinogenic.zzyjnl.cn
http://www.dtcms.com/a/281052.html

相关文章:

  • ethers.js-8-bigNmber和callstatic模拟
  • 【Android】日志的使用
  • 《黑马笔记》 --- C++核心编程
  • 10分钟搞定!Chatbox+本地知识库=你的私人语音导师:企业级全栈实现指南
  • etcd压缩历史版本
  • 安装MATLAB流程中遇到的问题
  • wpf Canvas 动态增加右键菜单
  • css:flex:1;是谁的缩写
  • compose、 pipe 组合函数实现
  • 20th Day| 235.二叉搜索树的最近公共祖先,701.二叉搜索树中的插入操作, 450.删除二叉搜索树中的节点
  • Postman + Newman + Jenkins 接口自动化测试
  • 使用canal同步分库分表数据,到 Elasticsearch
  • JavaScript事件
  • 【数据同化案例1】ETKF求解 Lorenz-63 模型的同化系统(完整MATLAB实现)
  • Java-特殊文件、日志技术
  • CherryStudio配置DeepSeek调用MCP服务实现任务自动化
  • Elasticsearch 9.x 搜索执行过程(源码解析)
  • AOP简化MyBatis分页:高效自动化方案
  • 第二十篇 Word文档自动化:Python批量生成、模板填充与内容修改,告别繁琐排版!
  • Web3 支付系统:面向企业和消费者的全面概述
  • 时间序列挖掘及建模
  • Linux系统集群部署模块之Keepalived双机热备
  • 使用SQLMAP的文章管理系统CMS的sql注入渗透测试
  • Java全栈工程师面试实录:从电商系统到AIGC的层层递进
  • WSF70N10G N 沟道 MOSFET 在蓝牙耳机中的应用分析
  • Linux获取CPU/GPU的温度
  • docker部署gbase8s(数据持久化)并用可视化工具管理
  • NuGet01-安装及使用
  • gRPC实战指南:像国际快递一样调用跨语言服务 —— 解密Protocol Buffer与HTTP/2的完美结合
  • 【GPIO】从STM32F103入门GPIO寄存器