Python 占用过多内存的对象列表
Python list of Objects taking up too much memory
我有以下代码,它创建了 class foo 的一百万个对象:
for i in range(1000000):
bar = foo()
list_bar.append(bar)
bar 对象只有 96 字节,由 getsizeof()
确定。但是,追加步骤需要将近 8GB 的内存。一旦代码退出循环,ram 使用量就会下降到预期的数量(列表的大小 + 一些开销~103MB)。只有当循环是 运行 时,ram 使用率才会飙升。为什么会这样?任何解决方法?
PS: 使用生成器不是一个选项,它必须是一个列表。
编辑: xrange
没有帮助,使用 Python 3. 内存使用率仅在循环执行期间保持高位,并在循环执行后下降循环通过。 append
会不会有一些不明显的开销?
这很可能是由于 foo()
构造函数进行了一些无意的 周期性 引用;通常 Python 对象会在引用计数降为零时立即释放内存;现在,当垃圾收集器有机会 运行.
时,这些将在稍后被释放
您可以尝试在 10000 次迭代后强制 GC 运行 以查看它是否保持内存使用不变。
import gc
n = 1000000
list_bar = [ None ] * n
for i in range(n):
list_bar[i] = foo()
if i % 10000 == 0:
gc.collect()
如果这减轻了内存压力,那么内存使用是因为一些引用循环。
调整列表大小会产生一些开销。如果你知道有多少个元素,那么你可以预先创建列表,例如:
list_bar = [ foo() for _ in xrange(1000000) ]
应该知道数组的大小而不需要调整它的大小;或创建包含 None
:
的列表
n = 1000000
list_bar = [ None ] * n
for i in range(n):
list_bar[i] = foo()
append
应该使用 realloc
来增加列表,但是旧的内存应该尽快释放;总而言之,对于最后为 100 MB 的列表,分配的所有内存的开销不应总计为 8G;操作系统可能错误地计算了使用的内存。
您如何衡量内存使用情况?
我怀疑您对第 3 方模块的使用可能是原因。也许第 3 方模块在初始化时暂时使用了大量内存。
此外,sys.getsizeof()
并不是对象所使用内存的准确指示。
例如:
from sys import getsizeof
class A(object):
pass
class B(object):
def __init__(self):
self.big = 'a' * 1024*1024*1024 # approx. 1 GiB
>>> getsizeof(A)
976
>>> a = A()
>>> getsizeof(a)
64
>>>
>>> getsizeof(B)
976
>>> b = B()
>>> getsizeof(b)
64
>>> getsizeof(b.big)
1073741873
实例化 b = B()
后,top
报告大约 1GiB 常驻内存使用情况。显然,getsizeof(b)
没有反映出来,returns 只有 64 个字节。
我有以下代码,它创建了 class foo 的一百万个对象:
for i in range(1000000):
bar = foo()
list_bar.append(bar)
bar 对象只有 96 字节,由 getsizeof()
确定。但是,追加步骤需要将近 8GB 的内存。一旦代码退出循环,ram 使用量就会下降到预期的数量(列表的大小 + 一些开销~103MB)。只有当循环是 运行 时,ram 使用率才会飙升。为什么会这样?任何解决方法?
PS: 使用生成器不是一个选项,它必须是一个列表。
编辑: xrange
没有帮助,使用 Python 3. 内存使用率仅在循环执行期间保持高位,并在循环执行后下降循环通过。 append
会不会有一些不明显的开销?
这很可能是由于 foo()
构造函数进行了一些无意的 周期性 引用;通常 Python 对象会在引用计数降为零时立即释放内存;现在,当垃圾收集器有机会 运行.
您可以尝试在 10000 次迭代后强制 GC 运行 以查看它是否保持内存使用不变。
import gc
n = 1000000
list_bar = [ None ] * n
for i in range(n):
list_bar[i] = foo()
if i % 10000 == 0:
gc.collect()
如果这减轻了内存压力,那么内存使用是因为一些引用循环。
调整列表大小会产生一些开销。如果你知道有多少个元素,那么你可以预先创建列表,例如:
list_bar = [ foo() for _ in xrange(1000000) ]
应该知道数组的大小而不需要调整它的大小;或创建包含 None
:
n = 1000000
list_bar = [ None ] * n
for i in range(n):
list_bar[i] = foo()
append
应该使用 realloc
来增加列表,但是旧的内存应该尽快释放;总而言之,对于最后为 100 MB 的列表,分配的所有内存的开销不应总计为 8G;操作系统可能错误地计算了使用的内存。
您如何衡量内存使用情况?
我怀疑您对第 3 方模块的使用可能是原因。也许第 3 方模块在初始化时暂时使用了大量内存。
此外,sys.getsizeof()
并不是对象所使用内存的准确指示。
例如:
from sys import getsizeof
class A(object):
pass
class B(object):
def __init__(self):
self.big = 'a' * 1024*1024*1024 # approx. 1 GiB
>>> getsizeof(A)
976
>>> a = A()
>>> getsizeof(a)
64
>>>
>>> getsizeof(B)
976
>>> b = B()
>>> getsizeof(b)
64
>>> getsizeof(b.big)
1073741873
实例化 b = B()
后,top
报告大约 1GiB 常驻内存使用情况。显然,getsizeof(b)
没有反映出来,returns 只有 64 个字节。