如果列表后的连续内存不足,Python如何处理列表扩展?
How does CPython handle list extend if there is insufficient contiguous memory after the list?
是可变的,当 Python list
被扩展时(例如,mylist.extend()
或 mylist += anotherlist
),列表的 id 不会改变。
我明白(至少在 CPython 中)列表在内存中是连续的(而且 id 恰好是列表头部的地址)。如果列表后面的内存已经高度碎片化并且无法分配列表扩展怎么办(即使有大量空闲 space,尽管该区域不连续)?分配失败?这是如何缓解的?
在 CPython 中,这是列表和元组分配方式的不同。对于列表,该对象包含一个指针指向为列表内容分配的内存。列表对象本身很小,永远不需要移动;它指向到的向量的地址可能会改变任意次数。
对于元组对象来说,大多数情况下它应该很小,元组内容的内存确实是直接在元组对象中分配的。但是元组不能调整大小,所以你的场景在那种情况下不会出现。
这是特定于实现的,但我假设您问的是 CPython。
如您所说,列表是连续的内存,但这些是指向 PyObjects 的 C 指针 (*PyObject
)。对象本身,无论是整数还是您自己的对象 class,都分配在动态内存中的某处,但(可能)不在连续内存中。
当列表第一次被分配时,会获得比所需更多的内存,在(概念上)右侧留下 "slack" 个条目。 list.append()
将只使用下一个松弛条目。当然最后都吃饱了。
此时执行内存重新分配。在 C 术语中,这是对 realloc()
的调用,但实现实际上可能不会为此使用 C 运行-time 堆。基本上,从动态内存中获得更大的内存分配,然后将列表中的所有元素复制到新列表中。请记住,我们正在复制指向 Python 对象的指针,而不是对象本身。
这样做会产生开销,但使用 slack 条目会减少开销。从这里可以看出 list.append()
比在列表的 "left" 上添加条目更有效。
如果由于新列表的内存不足而导致分配失败,您将收到内存不足错误。但是,如果您的内存不足,那么任何新的 Python 对象都可能导致这种情况。
堆碎片可能是个问题,但 Python 会尽力解决这个问题,这也是 Python 自己进行一些堆管理的原因之一。在最近的 Windows 实现中,使用了低级虚拟内存 API 而不是 C RTL,因此 Python 可以执行自己的内存管理。
是可变的,当 Python list
被扩展时(例如,mylist.extend()
或 mylist += anotherlist
),列表的 id 不会改变。
我明白(至少在 CPython 中)列表在内存中是连续的(而且 id 恰好是列表头部的地址)。如果列表后面的内存已经高度碎片化并且无法分配列表扩展怎么办(即使有大量空闲 space,尽管该区域不连续)?分配失败?这是如何缓解的?
在 CPython 中,这是列表和元组分配方式的不同。对于列表,该对象包含一个指针指向为列表内容分配的内存。列表对象本身很小,永远不需要移动;它指向到的向量的地址可能会改变任意次数。
对于元组对象来说,大多数情况下它应该很小,元组内容的内存确实是直接在元组对象中分配的。但是元组不能调整大小,所以你的场景在那种情况下不会出现。
这是特定于实现的,但我假设您问的是 CPython。
如您所说,列表是连续的内存,但这些是指向 PyObjects 的 C 指针 (*PyObject
)。对象本身,无论是整数还是您自己的对象 class,都分配在动态内存中的某处,但(可能)不在连续内存中。
当列表第一次被分配时,会获得比所需更多的内存,在(概念上)右侧留下 "slack" 个条目。 list.append()
将只使用下一个松弛条目。当然最后都吃饱了。
此时执行内存重新分配。在 C 术语中,这是对 realloc()
的调用,但实现实际上可能不会为此使用 C 运行-time 堆。基本上,从动态内存中获得更大的内存分配,然后将列表中的所有元素复制到新列表中。请记住,我们正在复制指向 Python 对象的指针,而不是对象本身。
这样做会产生开销,但使用 slack 条目会减少开销。从这里可以看出 list.append()
比在列表的 "left" 上添加条目更有效。
如果由于新列表的内存不足而导致分配失败,您将收到内存不足错误。但是,如果您的内存不足,那么任何新的 Python 对象都可能导致这种情况。
堆碎片可能是个问题,但 Python 会尽力解决这个问题,这也是 Python 自己进行一些堆管理的原因之一。在最近的 Windows 实现中,使用了低级虚拟内存 API 而不是 C RTL,因此 Python 可以执行自己的内存管理。