Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/323.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python数据结构内存占用行为怪异_Python_Memory Management_Heap_Programming Pearls - Fatal编程技术网

Python数据结构内存占用行为怪异

Python数据结构内存占用行为怪异,python,memory-management,heap,programming-pearls,Python,Memory Management,Heap,Programming Pearls,我在尝试一个编程珍珠: 给定一个包含最多1000万个7位整数且无重复项的文件。使用1.5Mb RAM按升序打印这些数字并只读取一次数据的有效方法是什么?只有1Mb的RAM而没有其他存储的后果是什么?如果允许重复,您的答案会有什么变化 为了创建一个测试用例I,生成8999999个数字并将它们写入一个文件。 然后,对于每一行,我开始将其插入到树中,最后创建一个trie结构 示例代码: from sys import getsizeof tree = dict() xtree = dict() f

我在尝试一个编程珍珠:

给定一个包含最多1000万个7位整数且无重复项的文件。使用1.5Mb RAM按升序打印这些数字并只读取一次数据的有效方法是什么?只有1Mb的RAM而没有其他存储的后果是什么?如果允许重复,您的答案会有什么变化

为了创建一个测试用例I,生成8999999个数字并将它们写入一个文件。 然后,对于每一行,我开始将其插入到树中,最后创建一个trie结构

示例代码:

from sys import getsizeof

tree = dict()
xtree = dict()
f = open("data2.txt", "r")
cnt = 0
for number in f:
    cnt += 1
    currTree = tree
    xtree[number] = dict()
    for n in number.strip():
        if n not in currTree:
            currTree[n] = dict()
        currTree = currTree[n]
f.close()

print(cnt)
print(getsizeof(tree))
print(getsizeof(xtree))
print(tree)
示例文件data2.txt有20条记录

生成的树是

现在的问题是,当我对构建的树进行内存大小调整时,在20行时,它显示了240字节的内存足迹

在100行时,树的大小变为368字节

在8999999行中,它还提供368个字节

我构建了一个名为
xtree
的辅助映射,它只提供数据

xtree和tree的大小以字节为单位


谁能解释一下这是怎么回事吗?。

您的
树只不过是一个最多有10个键值对的dict。在更大的树中,不再有任何键值对。在键值对内的值中有更多的值,但在dict中仍然只有10个键值对。一个大约有10个键值对、占用368字节的dict似乎与您所期望的差不多。1

正如文件所说:

只考虑直接归因于对象的内存消耗,而不考虑它所指对象的内存消耗

有关递归使用
getsizeof()
查找容器大小及其所有内容的示例,请参见

由于您实际上没有完全任意的数据结构,只有一个dict of等,并且虽然您有一些共享引用(例如,如果您在内存中已经有一个具有相同值的int时读取数字
1234567
,Python将只重用相同的对象),如果您试图验证是否可以容纳1.5MB,那么您确实需要最坏情况下的测量,因此您可能希望跳过已看到值的检查

所以,如果你想的话,你可以写一些简单的东西,而不是用那个食谱。但想法是一样的:

def total_dict_size(d):
    size = sys.getsizeof(d)
    if isinstance(d, dict):
        for key, value in d.items():
            size += sys.getsizeof(key) + total_dict_size(value)
    return size

另一方面,您的
xtree
是一个包含8999999个键值对的dict。做同样的信封背面计算,我希望它会有点低于300MB。相反,它有点超过300MB。够近了

您还将8999999个7位整数存储在堆中。假设有5百万个不同的整数不属于CPython预先创建和缓存的少数小值,就可以得到一些不错的整数。这些整数中的每一个都足够小,可以容纳一个30位数字,因此它们在64位CPython上每个都需要28个字节。因此,如果您在
tree
xtree
上调用上面的递归函数,那么在
sys.getsizeof(xtree)
中没有考虑到另外140MB(但事实上,它们被考虑到了,并且给出了最坏的度量实现)

因此,您在
xtree
和实际整数之间的总内存使用量可能在750MB左右,这不太符合
<1.5MB
的要求



一,。每个Python对象都有一些固定的头开销,比如refcount、指向类型的指针等,加上特定于类型的开销,比如大多数容器类型的长度。称之为64字节。然后,dict有一个哈希表。它需要比10个插槽大一点,以保持负载远低于1.0;叫它13个插槽。每个插槽都需要一个散列值、一个对键的引用和一个对值的引用,因此这是3个指针或24个字节。64 + 13 * 24 = 376. 因此,信封背面的计算只减少了8个字节…

您的
树只不过是一个最多有10个键值对的dict。在更大的树中,不再有任何键值对。在键值对内的值中有更多的值,但在dict中仍然只有10个键值对。一个大约有10个键值对、占用368字节的dict似乎与您所期望的差不多。1

正如文件所说:

只考虑直接归因于对象的内存消耗,而不考虑它所指对象的内存消耗

有关递归使用
getsizeof()
查找容器大小及其所有内容的示例,请参见

由于您实际上没有完全任意的数据结构,只有一个dict of等,并且虽然您有一些共享引用(例如,如果您在内存中已经有一个具有相同值的int时读取数字
1234567
,Python将只重用相同的对象),如果您试图验证是否可以容纳1.5MB,那么您确实需要最坏情况下的测量,因此您可能希望跳过已看到值的检查

所以,如果你想的话,你可以写一些简单的东西,而不是用那个食谱。但想法是一样的:

def total_dict_size(d):
    size = sys.getsizeof(d)
    if isinstance(d, dict):
        for key, value in d.items():
            size += sys.getsizeof(key) + total_dict_size(value)
    return size

另一方面,您的
xtree
是一个包含8999999个键值对的dict。做同样的信封背面计算,我希望它会有点低于300MB。相反,它有点超过300MB。够近了

您还将8999999个7位整数存储在堆中。假设有5百万个不同的整数不属于CPython预先创建和缓存的少数小值,就可以得到一些不错的整数。这些整数中的每一个都足够小,可以容纳一个30位数字,因此它们在64位CPython上每个都需要28个字节。因此,
sys.getsizeof(xtree)中没有考虑到另外140MB<