NumPy 内存分配结果不一致

Inconsistent results of NumPy memory allocation

提问人:Paul Jurczak 提问时间:10/9/2023 最后编辑:Paul Jurczak 更新时间:10/9/2023 访问量:57

问:

Ubuntu 22.04 上的这个 Python 3.11 脚本,大约有 16.4GB 内存可用(没有交换文件):

import numpy as np, psutil

print(f'{psutil.virtual_memory().available:,}')

try:
  a = np.empty((100_000_000_000), dtype='u1')  # variant A
  # a = np.empty((30_000_000_000), dtype='u1')  # variant B
  # a = np.ones((30_000_000_000), dtype='u1')  # variant C
  print(f'{a.size:,}')
except RuntimeError as e:
  print(e)

print('Done')

产生意想不到的不一致结果。

变体 A 按预期生成异常:

16,436,457,472
...
numpy.core._exceptions._ArrayMemoryError: Unable to allocate 93.1 GiB for an array with shape (100000000000,) and data type uint8

变体 B 意外分配的数组大于可用内存:

16,335,642,624
30,000,000,000
Done

变体 C 以静默方式失败:

16,337,346,560

有人可以解释变体 B 和 C 的行为吗?

Python 数组 numpy 内存不足 分配

评论

2赞 Brian61354270 10/9/2023
相关:Linux 内核:paging_init时零页分配的作用。当 numpy “分配”未初始化的字节时,它实际上并没有分配那么多物理内存。取而代之的是,你会得到一大堆零页,在你真正写到它们之前,物理页不会满足它们。这就是为什么变体 B “有效”并且不使用任何重要的内存,而变体 C 导致实际的内存分配被 OOM 杀手收割30_000_000_000
0赞 Paul Jurczak 10/9/2023
@Brian61354270 有没有办法让变体 C 抛出异常?
0赞 Brian61354270 10/9/2023
也许吧,但我不知道该怎么做。在极端情况下,您可以考虑自定义 numpy 的内存管理和/或 Python 的内存管理
1赞 Jérôme Richard 10/9/2023
psutil.virtual_memory().available似乎返回了我机器上的可用 RAM 量,但程序可以使用更多。首先,内存可以在主流系统上压缩(实际上在 Windows 上是默认的),然后交换文件/存储可用于存储部分 RAM,因此您通常可以分配和填充更多。更不用说可用的 RAM 量会动态变化,并且由于任何正在运行的(后台)进程,在分配后可能会更低。基于可用RAM的策略注定要失败。
0赞 Jérôme Richard 10/9/2023
如果你希望你的程序最近不会因此而崩溃,你需要在程序初始化期间分配(大部分)和填充数据。请注意,这应该填充目标数组。它速度较慢,但别无选择:出于安全原因,内核无法在不填充页面的情况下保留页面。您可以在 Linux 上的内核参数中禁用此安全性,但在大多数情况下,这是(非常)危险的(唯一可以的用例是未连接到互联网的计算机,仅运行非关键计算且用户访问受限)。np.full

答: 暂无答案