内存中 Python 列表的大小[重复]

2025-02-21 08:48:00
admin
原创
23
摘要:问题描述:我刚刚试验了内存中 Python 数据结构的大小。我写了以下代码片段:import sys lst1=[] lst1.append(1) lst2=[1] print(sys.getsizeof(lst1), sys.getsizeof(lst2)) 我在以下配置上获得了以下输出:Windows 7...

问题描述:

我刚刚试验了内存中 Python 数据结构的大小。我写了以下代码片段:

import sys
lst1=[]
lst1.append(1)
lst2=[1]
print(sys.getsizeof(lst1), sys.getsizeof(lst2))

我在以下配置上获得了以下输出:

  • Windows 7 64位,Python3.1:(52 40因此lst1有52个字节并且lst2有40个字节)

  • Ubuntu 11.4 32位,带有Python3.2:输出为48 32

  • Ubuntu 11.4 32位 Python2.7:48 36

有人能向我解释为什么虽然都是包含 1 的列表,但两个列表的大小却不同吗?

在该函数的 Python 文档中getsizeof我发现了以下内容:

...如果对象由垃圾收集器管理,则会增加额外的垃圾收集器开销。

在我的这个小例子中可能存在这种情况吗?


解决方案 1:

这里有一个更完整的交互式会话,它将帮助我解释发生了什么(Windows XP 32 位上的 Python 2.6,但这并不重要):

>>> import sys
>>> sys.getsizeof([])
36
>>> sys.getsizeof([1])
40
>>> lst = []
>>> lst.append(1)
>>> sys.getsizeof(lst)
52
>>> 

注意,空列表比包含元素的列表小一点[1]。但是,当添加元素时,它会变得大得多。

造成这种情况的原因在于Objects/listobject.cCPython 源代码中的实现细节。

空列表

当创建一个空列表时[],没有为元素分配任何空间 - 这可以在中看到PyList_New。36 字节是 32 位机器上列表数据结构本身所需的空间量。

包含一个元素的列表

当创建一个只有一个元素的列表时[1],除了列表数据结构本身所需的内存外,还会为一个元素分配空间。同样,这可以在 中找到PyList_Newsize作为参数,它计算:

nbytes = size * sizeof(PyObject *);

然后有:

if (size <= 0)
    op->ob_item = NULL;
else {
    op->ob_item = (PyObject **) PyMem_MALLOC(nbytes);
    if (op->ob_item == NULL) {
        Py_DECREF(op);
        return PyErr_NoMemory();
    }
    memset(op->ob_item, 0, nbytes);
}
Py_SIZE(op) = size;
op->allocated = size;

因此我们看到size = 1,为一个指针分配了空间。4个字节(在我的32位盒子上)。

附加到空列表

当调用append空列表时,会发生以下情况:

  • PyList_Append调用app1

  • app1询问列表的大小(并得到 0 作为答案)

  • app1然后调用list_resizesize+1在我们的例子中是 1)

  • list_resize有一个有趣的分配策略,其来源评论对此进行了总结。

这里是:

/* This over-allocates proportional to the list size, making room
* for additional growth.  The over-allocation is mild, but is
* enough to give linear-time amortized behavior over a long
* sequence of appends() in the presence of a poorly-performing
* system realloc().
* The growth pattern is:  0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
*/
new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6);

/* check for integer overflow */
if (new_allocated > PY_SIZE_MAX - newsize) {
    PyErr_NoMemory();
    return -1;
} else {
    new_allocated += newsize;
}

让我们做一些数学题

让我们看看我在文章开头的会话中引用的数字是如何达到的。

因此,36 个字节是 32 位列表数据结构本身所需的大小。对于单个元素,将为一个指针分配空间,因此需要 4 个额外字节 - 总共 40 个字节。到目前为止一切正常。

app1在空列表上调用时,它会list_resize使用 进行调用size=1。根据 的过度分配算法list_resize,1 之后的下一个最大可用大小是 4,因此将分配 4 个指针的位置。4 * 4 = 16 字节,而 36 + 16 = 52。

确实,一切都有道理:-)

解决方案 2:

您正在查看列表是如何分配的(我想也许您只是想看看事情有多大 - 在这种情况下,使用sys.getsizeof()

当某个东西被添加到列表中时,可能会发生以下两种情况之一:

  1. 多余的物品可放入空余空间。

  2. 需要额外的空间,因此需要创建一个新列表,并将内容复制过去,并添加额外的内容。

由于 (2) 的成本很高(复制内容,即使是指针,所需的时间也与要复制的内容数量成正比,因此随着列表变大,复制时间也会增加),我们希望不经常这样做。因此,我们不会只添加一点空间,而是添加整个块。通常,添加的数量与已在使用的数量相似 - 这样,数学计算得出,分配内存的平均成本(分摊到多次使用中)仅与列表大小成正比。

所以您看到的情况与此行为有关。我不知道具体细节,但如果[][1](或两者)是特殊情况,我不会感到惊讶,在这种情况下只分配了足够的内存(以在这些常见情况下节省内存),然后附加操作会执行上述“获取新块”的操作,从而添加更多内存。

但我不知道具体细节——这只是动态数组的一般工作方式。Python 中列表的确切实现将经过精细调整,以使其最适合典型的 Python 程序。所以我真正想说的是,您不能相信列表的大小会准确地告诉您它包含多少内容——它可能包含额外的空间,而额外的可用空间量很难判断或预测。

一个巧妙的替代方案是将列表做成对(value, pointer),其中每个指针指向下一个元组。这样,你可以逐步增加列表,尽管使用的总内存更高。这是一个链接列表(Python 使用的更像是一个向量或动态数组)。

Eli 的回答非常出色,他解释了[]和 的[1]分配是否准确,但将 附加到 会[]分配额外的块。代码中的注释就是我上面所说的(这称为“过度分配”,其数量与我们拥有的量成比例,因此平均(“摊销”)成本与大小成比例)。

解决方案 3:

以下是列表增长模式的快速演示。更改 range() 中的第三个参数将更改输出,使其看起来不像 listobject.c 中的注释,但简单地附加一个元素时的结果似乎完全准确。

allocated = 0
for newsize in range(0,100,1):
    if (allocated < newsize):
        new_allocated = (newsize >> 3) + (3 if newsize < 9 else 6)
        allocated = newsize + new_allocated;
    print newsize, allocated

解决方案 4:

公式根据系统架构而变化,32 位计算机为 (size-36)/4,64 位计算机为 (size-64)/8

36,64 - 基于机器的空列表的大小 4,8 - 基于机器的列表中单个元素的大小

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1325  
  IPD(Integrated Product Development)流程作为一种先进的产品开发管理模式,在众多企业中得到了广泛应用。它涵盖了从产品概念产生到产品退市的整个生命周期,通过整合跨部门团队、优化流程等方式,显著提升产品开发的效率和质量,进而为项目的成功奠定坚实基础。深入探究IPD流程的五个阶段与项目成功之间...
IPD流程分为几个阶段   4  
  华为作为全球知名的科技企业,其成功背后的管理体系备受关注。IPD(集成产品开发)流程作为华为核心的产品开发管理模式,其中的创新管理与实践更是蕴含着丰富的经验和深刻的智慧,对众多企业具有重要的借鉴意义。IPD流程的核心架构IPD流程旨在打破部门墙,实现跨部门的高效协作,将产品开发视为一个整体的流程。它涵盖了从市场需求分析...
华为IPD是什么   3  
  IPD(Integrated Product Development)研发管理体系作为一种先进的产品开发模式,在众多企业的发展历程中发挥了至关重要的作用。它不仅仅是一套流程,更是一种理念,一种能够全方位提升企业竞争力,推动企业持续发展的有效工具。深入探究IPD研发管理体系如何助力企业持续发展,对于众多渴望在市场中立足并...
IPD管理流程   3  
  IPD(Integrated Product Development)流程管理旨在通过整合产品开发流程、团队和资源,实现产品的快速、高质量交付。在这一过程中,有效降低成本是企业提升竞争力的关键。通过优化IPD流程管理中的各个环节,可以在不牺牲产品质量和性能的前提下,实现成本的显著降低,为企业创造更大的价值。优化产品规划...
IPD流程分为几个阶段   4  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用