当前位置: 首页 > 面试题库 >

内存中列表的大小

景阳平
2023-03-14
问题内容

我只是尝试了内存中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个字节。
  • 使用Python3.2的Ubuntu 11.4 32bit:输出为 48 32
  • Ubuntu 11.4 32位Python2.7: 48 36

谁能向我解释为什么两个大小都不同,尽管它们都是包含1的列表?

在getsizeof函数的python文档中,我发现了以下内容:...adds an additional garbage collector overhead if the object is managed by the garbage collector.在我的小示例中可能是这种情况吗?


问题答案:

这是一个更完整的交互式会议,它将帮助我解释发生了什么(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_New。鉴于size作为参数,它计算:

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;
}

让我们做一些数学

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

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

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

确实,一切都说得通:-)



 类似资料:
  • 问题内容: 如果我在python中有一个列表(或数组,字典…),它可能会超出可用的内存地址空间,(32位python)有哪些选项和相对速度?(除了不使列表变大之外)列表 可能 超出内存,但我无法事先知道。一旦开始超过75%,我将不再希望将该列表保留在内存中(或者无论如何都不会保留新项目),有没有办法在中途转换为基于文件的方法? 最佳(快进和快出)文件存储选项是什么? 只需要存储一个简单的数字列表。

  • 问题内容: 我听过关于Java程序中一个字节占用的内存量的意见不一。 我知道您在一个Java字节中最多可以存储+127,并且文档说一个字节只有8位,但是在这里我被告知实际上它占用的内存量与int相同,因此仅一种有助于代码理解而不是效率的类型。 谁能解决这个问题,这将是实现特定的问题吗? 问题答案: 好的,已经进行了很多讨论,而没有很多代码:) 这是一个快速基准测试。谈到这种事情,通常会有一些警告-

  • 问题内容: 我的磁盘上只有168MB的文件。这只是一个逗号分隔的单词,id的列表。该单词的长度可以为1-5个字符。有650万行。 我在python中创建了一个字典,将其加载到内存中,因此我可以针对该单词列表搜索传入的文本。当python将其加载到内存中时,它显示已使用的1.3 GB RAM空间。知道为什么吗? 假设我的word文件如下所示… 然后再加上650万。然后,我遍历该文件并创建一个字典(p

  • 问题内容: 我正在尝试加载大于h2o中的内存大小的数据。 H2o 博客提到: 这是连接到的代码: 给 我试图将169 MB的csv加载到h2o中。 这引发了错误, 这表示内存不足错误。 问题:如果H2o承诺加载大于其内存容量的数据集(如上面的博客引文所述,交换到磁盘机制),这是加载数据的正确方法吗? 问题答案: 由于性能太差,默认情况下前一会默认禁用“交换到磁盘”。流血边缘(不是最新稳定的)具有启

  • 我正在尝试在h2o中加载大于内存大小的数据。 H2o博客提到: 下面是连接到h2o 3.6.0.8的代码: 给 我试着把一个169 MB的csv加载到h2o中。 这抛出了一个错误, 这表示内存溢出错误。 问:如果H2opromise加载大于其内存容量的数据集(如上面的博客引述所说的交换到磁盘机制),这是加载数据的正确方法吗?

  • 我一直试图从内部存储中删除所选项目的列表,但无法这样做。 它什么都不做。我该怎么改还是有什么更好的办法?任何帮助都将不胜感激。