当没有分配新的内存时,Pypy内存使用量会增加

2024-07-05 14:53:24 发布

您现在位置:Python中文网/ 问答频道 /正文

我不确定这是否是其他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中的所有局部变量都是垃圾收集的情况下,其他任何东西都不应该增加内存使用量。在


Tags: 记忆内存程序列表returnifpypy使用量
2条回答

这里的一个问题是,你给数组赋值long,尽管你是模,PyPy似乎没有注意到这个数字仍然适合一个机器字。在

我可以想出两种方法来解决这个问题:

  1. 将分配给bin2[n+1]的值传递给int()。在
  2. 使用array.array()。在

前者只影响PyPy2,并导致Mac上稳定的内存占用约800MB,而后者似乎稳定在~1.4GB,而不管我是在PyPy2还是PyPy3中运行它。在

不过,我还没有完全运行这个程序,所以YMMV

哦,这是整数列表优化的一个坏例子。问题是这是从int的列表开始的:

bin2 = [0] * L

这在内部存储为整数数组。它通常要紧凑得多,即使在本例中它不会改变任何东西-因为在CPython上,它是一个包含同一对象L副本的列表{}。在

但问题是,很快,我们就会在列表中存储一个long。此时,我们需要将整个列表转换为可以存储任何内容的通用类型。但是!问题是我们看到了1亿个零,所以我们创建了1亿个0对象。这会立即造成3GB的内存压力,而列表本身的内存压力则为800MB。在

如果像这样初始化列表,我们可以检查是否不会出现问题,这样它就真正包含了1亿次相同的对象:

^{pr2}$

也就是说,在您的示例中,首先不需要列表包含1亿个元素。您可以将其初始化为:

bin2 = [1]

并使用bin2.append()。这使得程序可以更快地启动,并且在开始时不会占用大量内存。在

注意PyPy3仍然比CPython3使用更多的内存。在

相关问题 更多 >