考虑到列表只有76 MB,我试图理解为什么此python代码导致需要236 MB内存的进程。
import sys
import psutil
initial = psutil.virtual_memory().available / 1024 / 1024
available_memory = psutil.virtual_memory().available
vector_memory = sys.getsizeof([])
vector_position_memory = sys.getsizeof([1]) - vector_memory
positions = 10000000
print "vector with %d positions should use %d MB of memory " % (positions, (vector_memory + positions * vector_position_memory) / 1024 / 1024)
print "it used %d MB of memory " % (sys.getsizeof(range(0, positions)) / 1024 / 1024)
final = psutil.virtual_memory().available / 1024 / 1024
print "however, this process used in total %d MB" % (initial - final)
输出为:
vector with 10000000 positions should use 76 MB of memory
it used 76 MB of memory
however, this process used in total 236 MB
增加x10个位置(即positions = 100000000
)会增加x10的内存。
vector with 100000000 positions should use 762 MB of memory
it used 762 MB of memory
however, this process used in total 2330 MB
我的最终目标是尽可能多地吸收内存,以创建一个很长的列表。为此,我创建了这段代码来了解/预测基于可用内存的列表有多大。令我惊讶的是,我想python需要大量内存来管理我的列表。
为什么python使用那么多内存?它在做什么?关于如何预测python的内存需求以有效创建一个列表以使用几乎所有可用内存,同时防止OS进行交换的任何想法吗?
答案 0 :(得分:6)
getsizeof
函数仅包含列表本身使用的空间。
但是列表实际上只是一个指向int对象的指针数组,您创建了10000000个指针,并且每个指针也占用了内存(通常为24个字节)。
前几个数字(通常最多255个)是由解释程序预先创建和缓存的,因此它们实际上是免费的,而其余的不是。因此,您想添加以下内容:
int_memory = sys.getsizeof(10000)
print "%d int objects should use another %d MB of memory " % (positions - 256, (positions - 256) * int_memory / 1024 / 1024)
然后结果会更有意义。
但是请注意,如果您不是创建具有10M唯一整数的range
,而是使用0-10000的10M随机整数或0的10M副本创建该计算,将不再是正确的。因此,如果要处理这些情况,则需要执行类似的操作:隐藏到目前为止所见过的每个对象的id
,并跳过对同一id
的所有其他引用。
Python 2.x文档曾经有一个到旧的递归getsizeof
函数的链接,该函数可以执行此操作,等等……但是该链接已失效,因此将其删除。
The 3.x docs带有指向a newer one的链接,该链接可能在Python 2.7中起作用,也可能不起作用。 (我一眼便注意到,它对__future__
使用了print
语句,并从reprlib.repr
退回到repr
,所以它确实可以这样做。)
如果您想知道为什么每个int
都是24字节长(在64位CPython中;对于不同的平台和实现,当然是不同的):
CPython将每个内置类型表示为一个C结构,该结构至少包含用于refcount和指向该类型的指针的空间。对象还需要表示的任何实际值都是该值。 1 因此,最小的非单例类型每个实例将占用24个字节。
如果您想知道如何避免每个整数占用24个字节,答案是使用NumPy's ndarray
-或(由于某种原因而不能使用)stdlib的array.array
。 / p>
任何一种都可以指定“本机类型”,例如NumPy的np.int32
或i
的{{1}},然后创建一个数组,直接保存100M的这些本机类型值。每个值正好需要4个字节,加上头文件的数十个恒定字节的开销,这比array.array
的8个字节的指针要小得多,最后还有一点松弛,随长度,再加上一个list
对象,用于包装每个值。
使用int
会牺牲空间速度, 2 ,因为每次您要访问这些值之一时,Python都必须将其拉出并“装箱”为array.array
对象。
使用NumPy,您将同时获得 的速度和空间,因为NumPy可以让您在紧密优化的C循环中对整个数组执行矢量化操作。
1。用int
在Python中创建的非内置类型呢?它们有一个指向dict的指针,您可以在Python区域中以class
的形式查看该字典,其中包含您添加的所有属性。因此,根据__dict__
,它们为24个字节,但是当然,您还必须添加该字典的大小。
2。除非你不是。阻止系统进入交换地狱可能比装箱和拆箱使事情放慢的速度要快得多。而且,即使您没有避开巨大的悬崖,也可能仍然避开涉及虚拟机分页或缓存局部性的较小悬崖。