我不确定这是否是其他PyPy记忆问题的重复,但这里我将提供一个具体的例子。在
from __future__ import division
def mul_inv(a, m):
"""Modular multiplicative inverse, a^-1 mod m. Credit: rosettacode.org"""
m0 = m
x0, x1 = 0, 1
if m == 1: return 1
while a > 1:
assert m != 0, "a and m must be coprime"
q = a // m
a, m = m, a%m
x0, x1 = x1 - q * x0, x0
if x1 < 0: x1 += m0
return x1
M = 1000000009
L = 10**8
bin2 = [0] * L
bin2[0] = 1
for n in range(L-1):
bin2[n+1] = (bin2[n] * (4*n + 2) * mul_inv(n+1, M)) % M
if n % 10**5 == 0: print(n, bin2[n])
print(bin2[:20])
在Python3.6中,程序最多使用3-4GB,并一直运行到完成(ArminRigo的列表更改并没有显著改变这一点)。在Python2.7.13运行Pypy5.10.0时,程序很快达到8GB(我有多少RAM)并冻结。即使使用gc.collect()
调用,当n
大约为3.5*10^7时,程序也会耗尽内存。在
内存使用量从何而来?唯一的大内存使用应该是将bin2
初始化为一个10^8int列表。在假设mul_inv
中的所有局部变量都是垃圾收集的情况下,其他任何东西都不应该增加内存使用量。在
这里的一个问题是,你给数组赋值long,尽管你是模,PyPy似乎没有注意到这个数字仍然适合一个机器字。在
我可以想出两种方法来解决这个问题:
bin2[n+1]
的值传递给int()
。在array.array()
。在前者只影响PyPy2,并导致Mac上稳定的内存占用约800MB,而后者似乎稳定在~1.4GB,而不管我是在PyPy2还是PyPy3中运行它。在
不过,我还没有完全运行这个程序,所以YMMV
哦,这是整数列表优化的一个坏例子。问题是这是从int的列表开始的:
这在内部存储为整数数组。它通常要紧凑得多,即使在本例中它不会改变任何东西-因为在CPython上,它是一个包含同一对象}。在
L
副本的列表{但问题是,很快,我们就会在列表中存储一个
long
。此时,我们需要将整个列表转换为可以存储任何内容的通用类型。但是!问题是我们看到了1亿个零,所以我们创建了1亿个0
对象。这会立即造成3GB的内存压力,而列表本身的内存压力则为800MB。在如果像这样初始化列表,我们可以检查是否不会出现问题,这样它就真正包含了1亿次相同的对象:
^{pr2}$也就是说,在您的示例中,首先不需要列表包含1亿个元素。您可以将其初始化为:
并使用
bin2.append()
。这使得程序可以更快地启动,并且在开始时不会占用大量内存。在注意PyPy3仍然比CPython3使用更多的内存。在
相关问题 更多 >
编程相关推荐