RFC-0091 - zx_system_get_event ZX_SYSTEM_EVENT_IMMINENT_OUT_OF_MEMORY

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)发出内存压力事件信号。此逻辑可以轻松扩展,在“严重”和“OOM”之间添加新的“即将发生 OOM”水印。您可以通过内核命令行选项配置“即将发生 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_NORMALZX_SYSTEM_EVENT_MEMORY_PRESSURE_WARNINGZX_SYSTEM_EVENT_MEMORY_PRESSURE_CRITICAL 类似,它们也不需要 ZX_RIGHT_MANAGE_PROCESS 权限。换句话说,“正常”“警告”“严重”和“即将发生 OOM”事件可以使用 RootJobForInspect 协议,而 OOM 事件需要使用 RootJob 协议。

在内核中实现时,对现有内存回收逻辑所需的更改非常少。我们只需将另一个水印添加到传递给 pmm_init_reclamation() 的水印列表中即可。“即将发生 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 文档介绍了基于内核事件构建的用户空间内存压力信号。