You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NumPy内存分配结果异常:求解析B、C变体的行为原因

解析Numpy在Ubuntu 22.04下的内存分配异常行为

环境与测试代码

运行环境: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(1000亿元素的np.empty):如预期抛出内存不足异常
    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(300亿元素的np.empty):意外完成分配,无异常
    16,335,642,624
    30,000,000,000
    Done
    
  • 变体C(300亿元素的np.ones):无提示直接运行失败,仅输出可用内存后进程终止
    16,337,346,560
    

行为原因解析

变体B:np.empty的延迟内存分配

np.empty()的核心特性是不初始化数组内容,它仅向Linux内核申请一块虚拟地址空间,不会立即分配物理内存。Linux默认采用「写时复制」的延迟内存分配策略:只有当程序实际读写数组元素时,内核才会尝试分配对应的物理内存页。

在变体B的测试中,代码仅完成了数组对象的创建,没有任何访问元素的操作,因此物理内存从未被实际分配,自然不会触发内存不足的异常。此时数组只是一个「空架子」的虚拟地址空间,直到后续对数组进行读写操作时,才会真正触发物理内存分配,进而可能引发内存不足问题。

变体C:np.ones的立即内存分配与系统OOM Killer

np.ones()需要将数组的所有元素初始化为1,这意味着它会立即触发全量物理内存分配——内核需要为300亿个uint8元素(约27.9GB)分配对应的物理内存页,而系统可用内存仅16.4GB且无交换空间,远远无法满足需求。

此时Linux内核会启动**OOM Killer(内存不足杀手)**机制,直接终止占用内存最多的进程(这里就是Python进程)来释放内存。由于进程是被内核强制杀死的,Python没有机会执行异常捕获逻辑和后续的print语句,因此表现为无提示的运行失败。

内容的提问来源于stack exchange,提问作者Paul Jurczak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 01:20:08