列表的内存大小 python
Memory Size of list python
我正在用列表做一些试验,然后我发现了自引用列表。我搜索了 SO 并得到了一些关于它的基本问题的回答。但是当我尝试获取不同长度的自引用列表的内存大小时,我发现了一个有趣的模式
重现代码:
import sys
memory_size = {}
for length in range(50):
lst = []
for length_loop in range(length):
lst.append(lst)
memory_size[length] = sys.getsizeof(lst)
memory_size 的值:
{0: 64, 1: 96, 2: 96, 3: 96, 4: 96, 5: 128, 6: 128, 7: 128, 8: 128, 9: 192, 10: 192, 11: 192, 12: 192, 13: 192, 14: 192, 15: 192, 16: 192, 17: 264, 18: 264, 19: 264, 20: 264, 21: 264, 22: 264, 23: 264, 24: 264, 25: 264, 26: 344, 27: 344, 28: 344, 29: 344, 30: 344, 31: 344, 32: 344, 33: 344, 34: 344, 35: 344, 36: 432, 37: 432, 38: 432, 39: 432, 40: 432, 41: 432, 42: 432, 43: 432, 44: 432, 45: 432, 46: 432, 47: 528, 48: 528, 49: 528}
绘制上述数据点
Python 3.7.3 (default, Mar 27 2019, 16:54:48)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.5.0 -- An enhanced Interactive Python. Type '?' for help.
为什么自引用列表的内存大小在一定长度范围内保持不变,并在一定长度后增加?
而且内存大小的增加也是不同的
列表 总是 如果它们是通过追加增长的,则显示此模式。
要理解的一个关键点,sys.getsizeof
不考虑列表中引用的 objects,只考虑列表的大小 object 本身。现在,Python list
objects 被实现为引擎盖下的数组列表,所以本质上有一个 PyObject header (比如,16 字节开销或类似的),然后PyObject 指针的原始数组(为什么 它们可以是异构的,并引用它们自己)。
这个底层数组是过度分配的,它是re-sized以保证分摊constant-time.append
操作的方式。
换句话说,Python list
object 已经摊销了 constant-time .append
,所以像 for x in range(N): my_list.append(0)
这样的事情是 线性的时间操作,因为基础缓冲区不是每次迭代re-allocated。
看,你会看到与任何 object 相同的模式,例如 None
:
In [24]: import sys
...:
...: memory_size = {}
...:
...: for length in range(50):
...: lst = []
...: for length_loop in range(length):
...: lst.append(None)
...: memory_size[length] = sys.getsizeof(lst)
...:
In [25]: memory_size
Out[25]:
{0: 72,
1: 104,
2: 104,
3: 104,
4: 104,
5: 136,
6: 136,
7: 136,
8: 136,
9: 200,
10: 200,
11: 200,
12: 200,
13: 200,
14: 200,
15: 200,
16: 200,
17: 272,
18: 272,
19: 272,
20: 272,
21: 272,
22: 272,
23: 272,
24: 272,
25: 272,
26: 352,
27: 352,
28: 352,
29: 352,
30: 352,
31: 352,
32: 352,
33: 352,
34: 352,
35: 352,
36: 440,
37: 440,
38: 440,
39: 440,
40: 440,
41: 440,
42: 440,
43: 440,
44: 440,
45: 440,
46: 440,
47: 536,
48: 536,
49: 536}
为了说服您,这是您的 self-referening 列表:
In [26]: import sys
...:
...: memory_size = {}
...:
...: for length in range(50):
...: lst = []
...: for length_loop in range(length):
...: lst.append(lst)
...: memory_size[length] = sys.getsizeof(lst)
...:
In [27]: memory_size
Out[27]:
{0: 72,
1: 104,
2: 104,
3: 104,
4: 104,
5: 136,
6: 136,
7: 136,
8: 136,
9: 200,
10: 200,
11: 200,
12: 200,
13: 200,
14: 200,
15: 200,
16: 200,
17: 272,
18: 272,
19: 272,
20: 272,
21: 272,
22: 272,
23: 272,
24: 272,
25: 272,
26: 352,
27: 352,
28: 352,
29: 352,
30: 352,
31: 352,
32: 352,
33: 352,
34: 352,
35: 352,
36: 440,
37: 440,
38: 440,
39: 440,
40: 440,
41: 440,
42: 440,
43: 440,
44: 440,
45: 440,
46: 440,
47: 536,
48: 536,
49: 536}
个体大小的差异归结为 Python 版本和系统架构(例如,在 32 位系统上,指针是 4 个字节而不是 8 个字节,并且 Python 版本可以自由更改实现细节,例如空列表的大小)。注意,以上是 Python 3.7 上的 运行,如果我使用另一个环境:
(base) juanarrivillaga@173-11-109-137-SFBA ~ % python -c "import sys; print(f'{sys.version}\nEmpty List Size: {sys.getsizeof([])}')"
3.8.1 (default, Jan 8 2020, 16:15:59)
[Clang 4.0.1 (tags/RELEASE_401/final)]
Empty List Size: 56
答案可能就在其中。显然,大小的差异将取决于您的系统架构和 python 安装,增长大小可以通过 Python.
中列表的实现来解释
https://github.com/python/cpython/blob/master/Objects/listobject.c
我正在用列表做一些试验,然后我发现了自引用列表。我搜索了 SO 并得到了一些关于它的基本问题的回答。但是当我尝试获取不同长度的自引用列表的内存大小时,我发现了一个有趣的模式
重现代码:
import sys
memory_size = {}
for length in range(50):
lst = []
for length_loop in range(length):
lst.append(lst)
memory_size[length] = sys.getsizeof(lst)
memory_size 的值:
{0: 64, 1: 96, 2: 96, 3: 96, 4: 96, 5: 128, 6: 128, 7: 128, 8: 128, 9: 192, 10: 192, 11: 192, 12: 192, 13: 192, 14: 192, 15: 192, 16: 192, 17: 264, 18: 264, 19: 264, 20: 264, 21: 264, 22: 264, 23: 264, 24: 264, 25: 264, 26: 344, 27: 344, 28: 344, 29: 344, 30: 344, 31: 344, 32: 344, 33: 344, 34: 344, 35: 344, 36: 432, 37: 432, 38: 432, 39: 432, 40: 432, 41: 432, 42: 432, 43: 432, 44: 432, 45: 432, 46: 432, 47: 528, 48: 528, 49: 528}
绘制上述数据点
Python 3.7.3 (default, Mar 27 2019, 16:54:48)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.5.0 -- An enhanced Interactive Python. Type '?' for help.
为什么自引用列表的内存大小在一定长度范围内保持不变,并在一定长度后增加?
而且内存大小的增加也是不同的
列表 总是 如果它们是通过追加增长的,则显示此模式。
要理解的一个关键点,sys.getsizeof
不考虑列表中引用的 objects,只考虑列表的大小 object 本身。现在,Python list
objects 被实现为引擎盖下的数组列表,所以本质上有一个 PyObject header (比如,16 字节开销或类似的),然后PyObject 指针的原始数组(为什么 它们可以是异构的,并引用它们自己)。
这个底层数组是过度分配的,它是re-sized以保证分摊constant-time.append
操作的方式。
换句话说,Python list
object 已经摊销了 constant-time .append
,所以像 for x in range(N): my_list.append(0)
这样的事情是 线性的时间操作,因为基础缓冲区不是每次迭代re-allocated。
看,你会看到与任何 object 相同的模式,例如 None
:
In [24]: import sys
...:
...: memory_size = {}
...:
...: for length in range(50):
...: lst = []
...: for length_loop in range(length):
...: lst.append(None)
...: memory_size[length] = sys.getsizeof(lst)
...:
In [25]: memory_size
Out[25]:
{0: 72,
1: 104,
2: 104,
3: 104,
4: 104,
5: 136,
6: 136,
7: 136,
8: 136,
9: 200,
10: 200,
11: 200,
12: 200,
13: 200,
14: 200,
15: 200,
16: 200,
17: 272,
18: 272,
19: 272,
20: 272,
21: 272,
22: 272,
23: 272,
24: 272,
25: 272,
26: 352,
27: 352,
28: 352,
29: 352,
30: 352,
31: 352,
32: 352,
33: 352,
34: 352,
35: 352,
36: 440,
37: 440,
38: 440,
39: 440,
40: 440,
41: 440,
42: 440,
43: 440,
44: 440,
45: 440,
46: 440,
47: 536,
48: 536,
49: 536}
为了说服您,这是您的 self-referening 列表:
In [26]: import sys
...:
...: memory_size = {}
...:
...: for length in range(50):
...: lst = []
...: for length_loop in range(length):
...: lst.append(lst)
...: memory_size[length] = sys.getsizeof(lst)
...:
In [27]: memory_size
Out[27]:
{0: 72,
1: 104,
2: 104,
3: 104,
4: 104,
5: 136,
6: 136,
7: 136,
8: 136,
9: 200,
10: 200,
11: 200,
12: 200,
13: 200,
14: 200,
15: 200,
16: 200,
17: 272,
18: 272,
19: 272,
20: 272,
21: 272,
22: 272,
23: 272,
24: 272,
25: 272,
26: 352,
27: 352,
28: 352,
29: 352,
30: 352,
31: 352,
32: 352,
33: 352,
34: 352,
35: 352,
36: 440,
37: 440,
38: 440,
39: 440,
40: 440,
41: 440,
42: 440,
43: 440,
44: 440,
45: 440,
46: 440,
47: 536,
48: 536,
49: 536}
个体大小的差异归结为 Python 版本和系统架构(例如,在 32 位系统上,指针是 4 个字节而不是 8 个字节,并且 Python 版本可以自由更改实现细节,例如空列表的大小)。注意,以上是 Python 3.7 上的 运行,如果我使用另一个环境:
(base) juanarrivillaga@173-11-109-137-SFBA ~ % python -c "import sys; print(f'{sys.version}\nEmpty List Size: {sys.getsizeof([])}')"
3.8.1 (default, Jan 8 2020, 16:15:59)
[Clang 4.0.1 (tags/RELEASE_401/final)]
Empty List Size: 56
答案可能就在其中。显然,大小的差异将取决于您的系统架构和 python 安装,增长大小可以通过 Python.
中列表的实现来解释https://github.com/python/cpython/blob/master/Objects/listobject.c