关于python:sys.getsizeof()结果与结构大小并不完全相关

sys.getsizeof() results don't quite correlate to structure size

我正在尝试创建大小为1 MB的列表。当以下代码工作时:

1
2
3
dummy = ['a' for i in xrange(0, 1024)]
sys.getsizeof(dummy)
Out[1]: 9032

以下代码不起作用。

1
2
3
4
5
6
7
import os
import sys

dummy = []
dummy.append((os.urandom(1024))
sys.getsizeof(dummy)
Out[1]: 104

有人能解释为什么吗?

如果您想知道为什么我不使用第一个代码片段,我正在编写一个程序,通过编写一个for循环,将块(大小为1b、1kb和1MB)写入内存,来测试内存。

1
2
3
4
start = time.time()
for i in xrange(1, (1024 * 10)):  
     dummy.append(os.urandom(1024)) #loop to write 1 MB blocks into memory
end = time.time()


如果检查列表的大小,它将提供列表数据结构的大小,包括指向其组成元素的指针。它不会考虑元素的大小。

1
2
3
4
5
str1_size = sys.getsizeof(['a' for i in xrange(0, 1024)])
str2_size = sys.getsizeof(['abc' for i in xrange(0, 1024)])
int_size = sys.getsizeof([123 for i in xrange(0, 1024)])
none_size = sys.getsizeof([None for i in xrange(0, 1024)])
str1_size == str2_size == int_size == none_size

空表大小:sys.getsizeof([]) == 72。添加一个元素:EDOCX1[1]添加另一个元素:sys.getsizeof([1, 1]) == 88。所以每个元素加4个字节。为了得到1024字节,我们需要(1024 - 72) / 8 = 119元素。

包含119个元素的列表的大小:sys.getsizeof([None for i in xrange(0, 119)]) == 1080。这是因为列表为插入更多项目维护了额外的缓冲区,因此不必每次都调整大小。(对于107到126之间的元素数量,其大小与1080相同)。

所以我们需要的是一个不变的数据结构,它不需要保留这个缓冲区——tuple

1
2
3
4
5
6
empty_tuple_size = sys.getsizeof(())                     # 56
single_element_size = sys.getsizeof((1,))                # 64
pointer_size = single_element_size - empty_tuple_size    # 8
n_1mb = (1024 - empty_tuple_size) / pointer_size         # (1024 - 56) / 8 = 121
tuple_1mb = (1,) * n_1mb
sys.getsizeof(tuple_1mb) == 1024

因此,这是获得1MB数据结构的答案:(1,)*121

但请注意,这只是元组的大小和组成指针。对于总大小,实际上需要将单个元素的大小相加。

备选方案:

1
2
sys.getsizeof('') == 37
sys.getsizeof('1') == 38     # each character adds 1 byte

对于1 MB,我们需要987个字符:

1
sys.getsizeof('1'*987) == 1024

这是实际大小,而不仅仅是指针的大小。