Python:MemoryError 与 OverflowError 与即时系统冻结

Python: MemoryError vs OverflowError vs instant-system-freeze

最后一天,解决了另一个 Project Euler 我在管理 for i in range(n) 周期时遇到了麻烦。

我观察到 python 抛出不同的错误,取决于 x 变量 的大小。

这是一个 mcve 示例:

for i in range(x):
    pass

其中:

我试图理解pythonbuilt-in exception的意思:


最后,我的问题是:

为什么我得到 3 个不同的结果,仅取决于存储在 x 变量中的值?


注意:

好吧,range 尝试构建一个 完整的 列表,其中包含与 x.

一样多的项目

对于死亡即时交换情况,你可以估计,假设64位和一个固定的8字节整数,x = 10**9是值得的大约8点。因此,如果您的内存不多(考虑到已使用的 RAM),您就会明白系统交换的原因。

再往下看,如果函数无法分配足够大的块来保存结果(在 10**15 的情况下看起来相当大),则可能会引发 MemoryError

我不知道 range 的实现细节,但它可能使用 OverflowError 来确保元素的绝对最大数量(可能是为了防止MemoryError,基于实际可用内存)。
正如@ShadowRanger 在评论中提到的,如果结果的长度不能放入 size_t 变量(2**31(32 位)或 2**63( 64 位)) 因为它无法初始化这样的列表。

正如您所提到的,xrange 没有这个问题,因为它不会生成整个列表,而是在您每次迭代时生成一个值。这就是 iterator/generator 内存效率高的原因。


所以我快速浏览了一下,您可以看到 in the 2.7 source 为什么会抛出 OverflowError

range(x) 将首先创建一个大小为 x 的列表,然后用整数填充它。效果是:

  • x = 10**20OverflowError, because a list can only hold sys.maxsize(通常 2**31 - 12**63 - 1 分别用于 32 位和 64 位版本)项。
  • x = 10**15: MemoryError,因为内存不足,无法分配大小为 x 的(未初始化的)列表。
  • x = 10**9:将创建一个大小为 x 的列表;然后对于每个整数i < x,一个新的int对象将被创建并写入磁盘;每个都需要内存分配。 (这最终可能会或可能不会导致 MemoryError。)这会给 CPU 和内存带来很大的负担,从而降低您的机器速度。

总而言之,对于前两种情况,python 很明显任务无法完成,它会引发异常。在第三种情况下,它认为它可能能够完成任务,尽管速度很慢。