python - 列表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.
为什么自引用列表的内存大小在一定长度范围内保持不变,并在一定长度后增加?
而且内存大小的增加也是不同的
解决方案
如果列表是通过 append 增长的,则它们始终会显示此模式。
要理解的关键点,sys.getsizeof
不考虑列表中引用的对象,只考虑列表对象本身的大小。现在,Pythonlist
对象在底层实现为数组列表,因此基本上有一个 PyObject 标头(例如,16 字节开销或类似的),然后是一个原始的 PyObject 指针数组(这就是为什么它们可以是异构的,并引用自己)。
这个底层数组是overallocated的,并且它被重新调整大小以保证摊销的恒定时间.append
操作。换句话说,Pythonlist
对象已经摊销了 constant-time .append
,因此执行类似for x in range(N): my_list.append(0)
线性时间操作的操作,因为底层缓冲区不会在每次迭代时重新分配。
看,您会看到与任何对象相同的模式,例如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}
只是为了说服你,这里是你的自我参考列表:
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
推荐阅读
- r - 在 R 预测包中识别 stlm() arima 函数中的均值
- vba - 如何挂钩自定义表单上的按钮单击事件?
- ios - 将数据从 ViewController 传递到类
- javascript - 反应JS。自动滚动到pdf页面
- azure - 无法将 Pfx 证书上传到 Azure 密钥保管库
- python - MS 项目(*.mpp 文件)到 PowerBi
- javascript - 如何在 Selenium 中保留 Tampermonkey 脚本?
- html - Angular 上的 html 文件中的引导类没有智能感知 - Visual Studio 2017
- c# - 将自定义对象绑定到自定义用户控件时遇到问题
- javascript - 如何使 twig 全局变量在 javascript 库中可访问