| RFC-0091:zx_system_get_event ZX_SYSTEM_EVENT_IMMINENT_OUT_OF_MEMORY | |
|---|---|
| 状态 | 已接受 |
| 区域 |
|
| 说明 | 建议向 `zx_system_get_event()` 系统调用添加新事件 `ZX_SYSTEM_EVENT_IMMINENT_OUT_OF_MEMORY`。 |
| 问题 | |
| Gerrit 更改 | |
| 作者 | |
| 审核人 | |
| 提交日期(年-月-日) | 2021-04-12 |
| 审核日期(年-月-日) | 2021-05-04 |
摘要
此 RFC 提议向 zx_system_get_event() 系统调用添加新的事件类型 ZX_SYSTEM_EVENT_IMMINENT_OUT_OF_MEMORY。新的内核事件将在 ZX_SYSTEM_EVENT_OUT_OF_MEMORY 之前发出信号,以便于捕获接近 OOM 点的内存诊断信息。
设计初衷
当系统几乎耗尽可用物理内存而无法满足内存分配请求时,会发出 ZX_SYSTEM_EVENT_OUT_OF_MEMORY 信号。driver_manager 进程会等待此 OOM 事件,当收到信号时,它会要求 fshost 关闭文件系统,以便尽可能干净地重新启动设备。不过,目前还没有好的机制来捕获此时的有意义的内存状态,而这对于找出 OOM 的根本原因至关重要。
仅仅等待 OOM 事件,并在 OOM 发生时尝试写出内存报告是不可行的,因为这会与文件系统关闭发生竞争。因此,此 RFC 建议公开一个新事件 ZX_SYSTEM_EVENT_IMMINENT_OUT_OF_MEMORY,该事件将在尽可能接近 OOM 的时间发出信号,同时尝试在 OOM 之前提供一些缓冲空间,以便可靠地写出内存报告,而不是依赖于 ZX_SYSTEM_EVENT_OUT_OF_MEMORY。例如,如果系统空闲内存级别降至 50MB 时发出 ZX_SYSTEM_EVENT_OUT_OF_MEMORY 信号,则可以在空闲内存为 60MB 时发出 ZX_SYSTEM_EVENT_IMMINENT_OUT_OF_MEMORY 信号。
从长远来看,我们还希望在 OOM 时执行有序关机,这需要更高级别的用户空间组件(而非 driver_manager)等待 ZX_SYSTEM_EVENT_OUT_OF_MEMORY 事件,并关闭某些关键组件以及文件系统。这是一个范围更大的项目,届时我们将不得不重新审视 OOM 事件信号和报告代码路径。因此,此 RFC 中的提案可以看作是一个中间步骤,只需对现有设计进行最小程度的更改。memory_monitor 进程已在等待 Normal、Warning 和 Critical 事件,并在需要时生成内存报告,因此可以轻松扩展该进程,使其等待 Imminent-OOM 事件。如果报告生成由 OOM 上的有序关闭处理,此事件可能会在未来被移除;如果报告提供额外价值,我们可能会决定保留此事件。
设计
内核内存回收系统会根据三个内存水位标记(警告、严重和 OOM)发出内存压力事件信号。可以轻松扩展此逻辑,以在“严重”和“内存不足”之间添加新的“即将内存不足”水印。可以通过内核命令行选项配置 Imminent-OOM 与 OOM 水印之间的差值。
为了与现有的内存水位保持一致(也可以通过内核命令行进行配置),此增量将是以 MB 为单位的绝对内存量。这也意味着,单个值可能无法适用于所有平台,并且需要进行调整,这也是现有内存水位标记的共同属性。此外,内存报告生成本身也需要一定量的内存,在为此增量选择值时也应考虑这一点。
与 zx_system_get_event() 支持的其他内核事件一样,需要根作业的句柄。与 ZX_SYSTEM_EVENT_OUT_OF_MEMORY 不同,ZX_SYSTEM_EVENT_IMMINENT_OUT_OF_MEMORY 不需要 ZX_RIGHT_MANAGE_PROCESS 权限。这使得新事件类似于 ZX_SYSTEM_EVENT_MEMORY_PRESSURE_NORMAL、ZX_SYSTEM_EVENT_MEMORY_PRESSURE_WARNING 和 ZX_SYSTEM_EVENT_MEMORY_PRESSURE_CRITICAL,这些事件也不需要 ZX_RIGHT_MANAGE_PROCESS 权限。换句话说,Normal、Warning、Critical 和 Imminent-OOM 事件可以使用 RootJobForInspect 协议,而 OOM 事件需要使用 RootJob 协议。
在内核中实现时,只需对现有的内存回收逻辑进行极少的更改。我们只是向传递给 pmm_init_reclamation() 的水印列表添加了另一个水印。Imminent-OOM 级别与其他内存压力级别的唯一区别在于,它不会在内核中触发任何内存回收(逐出分页器支持的内存和可舍弃的内存)。此级别纯粹用作诊断级别;在此级别触发内存回收会改变事件最初旨在捕获的内存状态。因此,此新事件在 fuchsia.memorypressure 协议中不会有相应的信号,而该协议用于在用户空间中驱动内存回收。
实现
zx_system_get_event() 系统调用可以在单个 CL 中扩展;此更改不会以任何方式影响现有内核事件的等待者。新事件的等待者稍后可以在单独的 CL 中采用该事件。
性能
新事件不会影响现有事件等待者的性能。新事件在检索事件句柄和等待事件方面,也应具有与现有事件类似的性能特征。用于发出事件信号的内核性能也将与现有内核性能类似 - 当可用内存级别发生变化时,PMM 系统会找到最接近的内存水位,以便推断内存压力级别;该提案只是简单地添加一个新的水位,而不会更改其余的现有逻辑。
工效学设计
无。
向后兼容性
无。
安全注意事项
无。
隐私注意事项
无。
测试
将编写 Zircon 核心测试,以检索并等待 ZX_SYSTEM_EVENT_IMMINENT_OUT_OF_MEMORY。采用该事件时,还会编写单元测试来验证客户端行为。
文档
需要更新 zx_system_get_event() 的系统调用文档。
此外,我们还将在内核概念文档中添加一个条目,说明各种内存压力级别背后的动机、每个级别下预期的响应,以及它们如何与系统的其余部分相关联。
缺点、替代方案和未知因素
缺点:内存报告可能不够精确
由于事件是在 OOM 之前发出的信号,因此捕获的内存状态不会与 OOM 完全一致。不过,只要 OOM 水位与实际内存用量之间的差值足够小(几十 MB),这仍然有助于诊断 OOM。
我们可能会遇到以下情况:生成报告后没有出现 OOM,即设备在发生 Imminent-OOM 事件后能够以某种方式恢复。尽管此类报告不会关联 OOM 事件,但它仍然是有用的内存数据,因为它仍然表明内存使用量有所增加,值得调查。
如果内存分配快速飙升,事件的等待者也可能无法生成报告。在这种情况下,仍需通过在本地重现问题来诊断问题,同时并行收集内存指标。报告仍应能够捕获大多数 OOM 的内存诊断信息,因为非常快速的分配峰值很少见。
替代方案 1:使用现有活动而非新活动
ZX_SYSTEM_EVENT_OUT_OF_MEMORY 无法用于可靠地写出内存报告。这是因为 OOM 事件用于驱动文件系统关闭,因此我们可能无法及时写出报告。
通过将 OOM 信号处理从 driver_manager 移至另一个可以驱动更井然有序的关机的用户空间组件,可以更改此互动 - 首先写出报告,然后关闭文件系统。此方法需要进行一些同步,以确保在文件系统关闭之前成功写出报告。由于在发出 OOM 信号时,我们现在会执行更多工作,因此可能还需要放宽 OOM 水印和发出 OOM 信号后的重启延迟时间间隔。对 OOM 信号处理方式的这一更改与 OOM 时有序关闭的更大范围的努力(在“动机”部分中简要介绍)相关联,这可能在未来进行。
在发生 OOM 之前发出的另一个现有信号是 ZX_SYSTEM_EVENT_MEMORY_PRESSURE_CRITICAL,我们确实使用该信号来写入内存报告。不过,严重内存水位与 OOM 水位之间的距离足够远,因此这些报告可能会遗漏更接近 OOM 的重要内存状态变化。
替代方案 2:更丰富的 API,可用于更多诊断事件
我们可以提供一个替代 API,让用户可以指定多个自定义诊断内存级别,以便在达到这些级别时收到通知,而不是公开接近 OOM 的专用事件。这样一来,API 会更加灵活,并且将来更容易扩展。不过,目前还没有具体的用例表明此类 API 会很有用。
其他可能需要捕获诊断信息的内存压力级别为“警告”和“严重”。对于这些级别,我们可以直接使用指示级别更改的内核事件。我们已经针对严重级别执行此操作。OOM 级别在这方面比较特殊,因为无法在发生 OOM 时准确捕获诊断信息。在理想情况下,我们希望在发生 OOM 时捕获状态。由于无法实现这一点,我们需要一个足够接近 OOM 的其他信号,以便能够捕获相关状态,但又不能太接近,以免遇到类似的问题而无法写入报告。
在先技术和参考资料
zx_system_get_event 文档介绍了内核内存事件的运作方式。fuchsia.memorypressure 文档介绍了基于内核事件构建的用户空间内存压力信号。