【问题标题】:How is memory handled once touched for the first time in numpy.zeros?在 numpy.zeros 中第一次触及内存时如何处理内存?
【发布时间】:2021-12-31 10:07:09
【问题描述】:

我最近看到,当通过np.emptynp.zeros 创建一个numpy 数组时,该numpy 数组的内存实际上并没有像this answer(和this question)中讨论的那样由操作系统分配,因为numpy利用calloc 分配数组的内存。

实际上,在您尝试访问之前,操作系统甚至不会“真正”分配该内存。

因此,

l = np.zeros(2**28)

不会增加系统报告的已用内存,例如htop。 只有一次我触摸内存,例如通过执行

np.add(l, 0, out=l)

使用的内存增加了。

由于这种行为,我有几个问题:

1。被感动的记忆是在幕后复制的吗?

如果我只是在一段时间后才触摸内存块,操作系统是否会在后台复制 numpy 数组的内容以保证内存是连续的?

i = 100
f[:i] = 3

while True:
    ... # Do stuff
    f[i] = ... # Once the memory "behind" the already allocated chunk of memory is filled
                # with other stuff, does the operating system reallocate the memory and
                # copy the already filled part of the array to the new location?
    i = i + 1

2。触摸最后一个元素

由于numpy数组的内存在内存中是连续的,所以我坚持

f[-1] = 3

可能需要分配整个内存块(不涉及整个内存)。 但是,事实并非如此,htop 中使用的内存不会随着数组的大小而增加。 为什么不是这样?

【问题讨论】:

  • 这是一个实现细节,你作为 python 级别的编码器无法操作。

标签: python python-3.x numpy memory calloc


【解决方案1】:

在您尝试访问之前,操作系统甚至不会“真正”分配该内存

这取决于目标平台(通常是操作系统及其配置)。一些平台直接在物理内存中分配页面(例如,AFAIK XBox 和一些嵌入式平台一样)。但是,主流平台确实是这样做的。

1.被感动的记忆是在幕后复制的吗?
如果我只在一段时间后触摸内存块,操作系统是否会在后台复制 numpy 数组的内容以保证内存是连续的?

分配在虚拟内存中执行。当在给定的内存页面(固定大小的块,例如 4 KiB)上完成第一次触摸时,操作系统将虚拟页面映射到物理页面。因此,当您只设置数组的一项时,只有一页会被物理映射(除非该项目跨越两页,这仅在病态情况下发生)。

对于一组连续的虚拟页面,物理页面可能不连续。但是,这不是问题,您不应该关心它。这主要是操作系统的工作。话虽如此,现代处理器有一个名为 TLB 的专用单元来将虚拟地址(您可以通过调试器看到的)转换为物理地址(因为这种转换相对昂贵和性能至关重要)。

由于分页,Numpy 数组的内容不会被重新分配或复制(至少从用户的角度来看,即在虚拟内存中)。

2。触摸最后一个元素
我认为f[-1] = 3 可能需要分配整个内存块(而不涉及整个内存)。但是,事实并非如此,htop 中使用的内存不会随着数组的大小而增加。为什么不是这样?

只有与 Numpy 数组关联的虚拟内存中的最后一页被映射,这要归功于分页。这就是为什么您没有看到 htop 有很大变化的原因。但是,如果您仔细观察,您应该会看到细微的变化(您平台上的页面大小)。否则,这应该意味着由于其他先前的回收分配,该页面已经被映射。实际上,分配库可以预先分配内存区域以加快分配速度(通过减少对操作系统的缓慢请求的数量)。该库还可以在 Numpy 释放内存时保持内存映射,以加快下一次分配的速度(因为不必取消映射内存然后再次映射)。这在实践中不太可能发生在大型数组中,因为对内存消耗的影响太高了。

【讨论】:

  • 感谢您的精彩解释 :) 我有一个后续问题:这是否意味着我们稍后可能会在第一次触摸内存页面并且操作系统尝试映射内存页面时看到内存错误虚拟内存页面到物理内存不足?
  • 没错!好问题。您可以分配一大块(虚拟)内存,然后填充它以进行测试。你应该得到一个程序崩溃。在具有交换(位于用于存储不适合 RAM 的内存数据的存储设备上的文件/空间)的系统上可能需要一段时间。请注意,系统可能会遗憾地(几乎)冻结之前,因为将最后剩余的页面映射到物理内存通常要昂贵得多。
猜你喜欢
  • 1970-01-01
  • 2015-01-26
  • 2012-12-27
  • 2011-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多