为什么我的Python2.7进程使用的内存量会越来越大?

为什么我的Python2.7进程使用的内存量会越来越大?,python,memory,memory-management,Python,Memory,Memory Management,考虑到这个列表只有76MB长,我试图理解为什么这个python代码会导致一个需要236MB内存的进程 import sys import psutil initial = psutil.virtual_memory().available / 1024 / 1024 available_memory = psutil.virtual_memory().available vector_memory = sys.getsizeof([]) vector_position_memory = sy

考虑到这个列表只有76MB长,我试图理解为什么这个python代码会导致一个需要236MB内存的进程

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个位置,即位置=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的内存需求,从而有效地创建一个列表,在使用几乎所有可用内存的同时防止操作系统进行交换吗?

该函数只包括列表本身使用的空间

但是这个列表实际上只是一个指向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个唯一整数的范围,而是创建一个0-10000之间的10M个随机整数或0的10M个副本,那么该计算将不再正确。因此,如果你想处理这些情况,你需要做一些事情,比如隐藏你迄今为止看到的每个对象的id,并跳过对同一id的任何附加引用

Python2.x文档曾经有一个指向旧的递归getsizeof函数的链接,该函数可以实现这一点,等等……但是该链接已经失效,所以被删除了

有到的链接,该链接在Python 2.7中可能适用,也可能不适用。我从快速浏览中注意到,它使用了一个_future __)语句进行打印,并从reprlib.repr返回到repr,所以它可能会这样做

如果您想知道为什么64位CPython中的每个int都是24字节长;当然,对于不同的平台和实现,这是不同的:

CPython将每个内置类型表示为一个C结构,其中至少包含一个refcount空间和一个指向该类型的指针。对象需要表示的任何实际值都是除此之外的。1因此,最小的非单例类型将为每个实例占用24字节

如果您想知道如何避免每个整数最多使用24个字节,那么答案是使用-或者,如果出于某种原因,不能使用stdlib的

任何一种方法都允许您指定本机类型,如np.int32表示NumPy,i表示array.array,并创建一个数组,直接保存100M的这些本机类型值。每个值正好需要4个字节,加上几十个恒定字节的头开销,这比列表的8个字节的指针要小得多,再加上末尾的一点松弛,随着长度的增加而增加,再加上一个整型对象包装每个值

使用array.array,您正在为空间牺牲速度,2因为每次您想要访问其中一个值时,Python都必须将其取出并将其作为int对象装箱

使用NumPy,您将获得速度和空间,因为NumPy将允许您在一个经过严格优化的C循环中对整个阵列执行矢量化操作

一,。那么您在Python中使用类创建的非内置类型呢?它们有一个指向dict的指针,您可以从pythonland中看到它是uu dict uu-,它保存您添加的所有属性。根据getsizeof,它们是24个字节,但是当然你还必须添加该dict的大小

二,。除非你不是。防止您的系统进入交换地狱可能比装箱和拆箱慢很多。而且,即使您没有避开那个巨大的悬崖,您也可能会避开涉及VM分页或缓存位置的较小悬崖。

该函数只包括列表本身使用的空间

但是这个列表实际上只是一个指向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个唯一整数的范围,而是创建一个0-10000之间的10M个随机整数或0的10M个副本,那么该计算将不再正确。因此,如果你想处理这些情况,你需要做一些事情,比如隐藏你迄今为止看到的每个对象的id,并跳过对同一id的任何附加引用

Python2.x文档曾经有一个指向旧的递归getsizeof函数的链接,该函数可以实现这一点,等等……但是该链接已经失效,所以被删除了

链接到,whic h在Python2.7中可以工作,也可以不工作。我从快速浏览中注意到,它使用了一个_future __)语句进行打印,并从reprlib.repr返回到repr,所以它可能会这样做

如果您想知道为什么64位CPython中的每个int都是24字节长;当然,对于不同的平台和实现,这是不同的:

CPython将每个内置类型表示为一个C结构,其中至少包含一个refcount空间和一个指向该类型的指针。对象需要表示的任何实际值都是除此之外的。1因此,最小的非单例类型将为每个实例占用24字节

如果您想知道如何避免每个整数最多使用24个字节,那么答案是使用-或者,如果出于某种原因,不能使用stdlib的

任何一种方法都允许您指定本机类型,如np.int32表示NumPy,i表示array.array,并创建一个数组,直接保存100M的这些本机类型值。每个值正好需要4个字节,加上几十个恒定字节的头开销,这比列表的8个字节的指针要小得多,再加上末尾的一点松弛,随着长度的增加而增加,再加上一个整型对象包装每个值

使用array.array,您正在为空间牺牲速度,2因为每次您想要访问其中一个值时,Python都必须将其取出并将其作为int对象装箱

使用NumPy,您将获得速度和空间,因为NumPy将允许您在一个经过严格优化的C循环中对整个阵列执行矢量化操作

一,。那么您在Python中使用类创建的非内置类型呢?它们有一个指向dict的指针,您可以从pythonland中看到它是uu dict uu-,它保存您添加的所有属性。根据getsizeof,它们是24个字节,但是当然你还必须添加该dict的大小


二,。除非你不是。防止您的系统进入交换地狱可能比装箱和拆箱慢很多。而且,即使您没有避开那个巨大的悬崖,您也可能会避开涉及VM分页或缓存位置的较小悬崖。

听起来很有可能。但它提出了另一个问题,为什么int对象应该使用24字节@snoopy CPython中的每个对象都必须至少包含一个refcount和一个指向其类型的指针。因此,在64位平台上,最小的非单例对象是24字节。这是一个多么好的答案啊!感谢您所传递的所有知识!听起来很有可能。但它提出了另一个问题,为什么int对象应该使用24字节@snoopy CPython中的每个对象都必须至少包含一个refcount和一个指向其类型的指针。因此,在64位平台上,最小的非单例对象是24字节。这是一个多么好的答案啊!感谢您所传递的所有知识!