简体   繁体   English

为什么空列表的大小不是 0 字节?

[英]Why isn't the size of an empty list 0 bytes?

Today itself I ran the code given below in Python 2.7.13 and found that the list size isn't 0 when it is empty:今天,我在Python 2.7.13 中运行了下面给出的代码,发现列表大小在为空时不是 0:

import sys
data = []
for k in range(n):
    a = len(data)
    b = sys.getsizeof(data)
    print('Length:{0:3d};Size in bytes:{1:4d}'.format(a,b))
    data.append(None)

Output on my Machine:我机器上的输出:

Length: 0; Size in bytes : 72
Length: 1; Size in bytes : 104
Length: 2; Size in bytes : 104
Length: 3; Size in bytes : 104
Length: 4; Size in bytes : 104
Length: 5; Size in bytes : 136
Length: 6; Size in bytes : 136
Length: 7; Size in bytes : 136
Length: 8; Size in bytes : 136
Length: 9; Size in bytes : 200
Length: 10; Size in bytes : 200
Length: 11; Size in bytes : 200
Length: 12; Size in bytes : 200
Length: 13; Size in bytes : 200
Length: 14; Size in bytes : 200
Length: 15; Size in bytes : 200
Length: 16; Size in bytes : 200
Length: 17; Size in bytes : 272
Length: 18; Size in bytes : 272
Length: 19; Size in bytes : 272

I want to know why is this happening?我想知道为什么会这样?

It seems that Python is reserving memory for something.似乎 Python 正在为某些东西保留内存。 What is that something??那是什么东西??

Because the size of the list, as returned from sys.getsizeof , doesn't include only the elements that list contains.因为从sys.getsizeof返回的列表大小不仅包括列表包含的元素。

Every object in Python is represented by a C -struct; Python 中的每个对象都由一个C结构体表示; this struct contains pointers to all the things that make the list a list (its methods, mainly).这个结构包含指向所有使列表成为列表的东西的指针(主要是它的方法)。 It's also taken into consideration when sys.getsizeof is invoked.调用sys.getsizeof时也会考虑到sys.getsizeof一点。

You can always take a look at the implementation of list.__sizeof__ in the master branch of the CPython repository on GitHub:您可以随时查看 GitHub 上 CPython 存储库的 master 分支中list.__sizeof__实现

static PyObject *
list___sizeof___impl(PyListObject *self)
{
    Py_ssize_t res;

    res = _PyObject_SIZE(Py_TYPE(self)) + self->allocated * sizeof(void*);
    return PyLong_FromSsize_t(res);
}

(Trimmed off unrelated arg clinic output.) (修剪掉不相关的 arg 诊所输出。)

The sizeof function for 2.x does the same thing. 2.xsizeof 函数做同样的事情。

The return value res also includes the size of the list object type _PyObject_SIZE(Py_Type(self)) .返回值res还包括列表对象类型_PyObject_SIZE(Py_Type(self))

Since everything in Python is an object, this behavior can be observed everywhere, ex, integer 0 :由于 Python 中的一切都是对象,因此可以在任何地方观察到这种行为,例如整数0

>>> getsizeof(0)
24

while you wouldn't normally expect this, it makes perfect sense when you realize everything in Python has "additional baggage" which allows behavior we take for granted.虽然您通常不会期望这一点,但当您意识到 Python 中的所有内容都有“额外的包袱”时,这是完全有道理的,这允许我们认为理所当然的行为。

Python is implemented in C, and as such will be storing data in a C struct. Python 是用 C 实现的,因此会将数据存储在 C 结构中。

Remember that all things are 'objects' - objects must have a type and an object size, even if they don't store anything .请记住,所有事物都是“对象”——对象必须具有类型和对象大小,即使它们不存储任何内容

Below are the PyObject_VAR_HEAD and PyListObject C datatypes.下面是PyObject_VAR_HEADPyListObject C 数据类型。

#define PyObject_VAR_HEAD               \
    PyObject_HEAD                       \
    Py_ssize_t ob_size; /* Number of items in variable part */

typedef struct {
    PyObject_VAR_HEAD
    /* Vector of pointers to list elements.  list[0] is ob_item[0], etc. */
    PyObject **ob_item;

    /* ob_item contains space for 'allocated' elements.  The number
     * currently in use is ob_size.
     * Invariants:
     *     0 <= ob_size <= allocated
     *     len(list) == ob_size
     *     ob_item == NULL implies ob_size == allocated == 0
     * list.sort() temporarily sets allocated to -1 to detect mutations.
     *
     * Items must normally not be NULL, except during construction when
     * the list is not yet visible outside the function that builds it.
     */
    Py_ssize_t allocated;
} PyListObject;

Remember that sys.getsizeof() will return the underlying memory usage, not something that you really need to consider or worry about from Python:请记住, sys.getsizeof()将返回底层内存使用情况,而不是您真正需要从 Python 考虑或担心的事情:

Return the size of an object in bytes.以字节为单位返回对象的大小。

Only the memory consumption directly attributed to the object is accounted for, not the memory consumption of objects it refers to.只考虑直接归因于对象的内存消耗,而不是它所引用的对象的内存消耗。

Additionally, as your test shows, there is an amount of pre-allocation going on.此外,正如您的测试所示,有大量的预分配正在进行。 New memory is not associated with the list on every call to append() .每次调用append()新内存都不会与list相关联。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM