Fre*_*ong 1 python memory memory-management
我试图理解为什么这个python代码导致一个需要236 MB内存的进程,考虑到该列表只有76 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)
Run Code Online (Sandbox Code Playgroud)
输出是:
vector with 10000000 positions should use 76 MB of memory
it used 76 MB of memory
however, this process used in total 236 MB
Run Code Online (Sandbox Code Playgroud)
添加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
Run Code Online (Sandbox Code Playgroud)
我的最终目标是尽可能多地记忆,以创建一个很长的列表.为此,我创建了这段代码,以便根据可用内存来理解/预测列表的大小.令我惊讶的是,我猜想python需要大量的内存来管理我的列表.
为什么python会使用这么多内存?!这是怎么回事?有关如何预测python的内存需求以有效创建列表以使用几乎所有可用内存同时阻止操作系统进行交换的任何想法?
该getsizeof函数仅包括列表本身使用的空间.
但是该列表实际上只是一个指向int对象的指针数组,并且您创建了10000个这些指针,并且每个指针都占用了内存 - 通常是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)
Run Code Online (Sandbox Code Playgroud)
然后结果会更有意义.
但请注意,如果您没有创建range具有10M唯一整数的内容,而是从0-10000或10M副本0开始的10M随机整数,则该计算将不再正确.因此,如果想要处理这些情况,您需要执行一些操作,例如存储id到目前为止您看到的每个对象,并跳过对其相同的任何其他引用id.
Python 2.x文档曾经有一个链接到一个旧的递归getsizeof函数,它可以做到这一点,而且更多......但是这个链接已经死了,所以它被删除了.
3.x文档有一个更新的链接,在Python 2.7中可能有效,也可能无效.(我从它采用的是快速浏览发现__future__语句print,并落在后面reprlib.repr来repr,所以它可能不会.)
如果你想知道为什么每个int都是24字节长(在64位CPython中;当然,它对于不同的平台和实现是不同的):
CPython将每个内置类型表示为一个C结构,它至少包含一个refcount空间和一个指向该类型的指针.除此之外,对象需要表示的任何实际值.1因此,最小的非单例类型将占用每个实例24个字节.
如果您想知道如何避免每个整数使用24个字节,答案是使用NumPy的ndarray -or,如果由于某种原因你不能使用stdlib array.array.
任何一个都允许您指定"本机类型",如np.int32NumPy或ifor array.array,并创建一个直接保存100M这些本机类型值的数组.这将是每个值恰好4个字节,加上几十个常量字节的头开销,比一个list8字节的指针要小很多,再加上一些与长度一致的松弛,加上一个int对象包装每个值.
使用array.array,你牺牲了空间的速度,2因为每次你想要访问其中一个值时,Python必须把它拉出来并将它"装箱"为一个int对象.
使用NumPy,您可以获得速度和空间,因为NumPy将允许您在紧密优化的C循环中对整个阵列执行矢量化操作.
1.你用Python创建的非内置类型怎么样class?它们有一个指向dict的指针 - 你可以从Python-land看到它__dict__- 它包含你添加的所有属性.因此它们是24字节getsizeof,但当然你还必须添加该字典的大小.
2.除非你不是.防止你的系统进入交换地狱可能会比拳击加速更多的东西,而拆箱会减慢速度.而且,即使你没有避开那个巨大的悬崖,你仍然可以避免涉及VM分页或缓存局部的较小悬崖.