我试图在嵌套的dicts上下文中理解Python中的内存使用。我有以下的命令:
>>> outer = {
... 'name': 'John Smith',
... 'books': [
... {'name': 'The Goal', 'author': 'Goldratt'},
... {'name': 'The Source', 'author': 'Michener'},
... {'name': 'A Walk in the Woods', 'author': 'Bryson'},
... {'name': 'Alice in Wonderland', 'author': 'Carroll'},
... ]
... }
它在内存中有一个地址:
>>> hex(id(outer))
'0x2299c5ee680'
我把第二本书赋值给一个变量:
>>> second_book = outer['books'][1]
如果我检查second_book
的内存地址和outer
中的对象,它们是相同的,这对我来说是有意义的:
>>> hex(id(outer['books'][1]))
'0x2299c5d2cc0'
>>> hex(id(second_book))
'0x2299c5d2cc0'
我现在删除对outer
和garbage-collect的引用:
>>> del outer
>>> gc.collect()
0
正如预期的那样,outer
不再存在:
>>> hex(id(outer))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'outer' is not defined
second_book
仍然存在,并且仍然引用内存中的相同地址。我不确定会是这样,所以看到这个很有趣。
>>> second_book
{'name': 'The Source', 'author': 'Michener'}
>>> hex(id(second_book))
'0x2299c5d2cc0'
我的问题:剩余的内存(以前被整个outer
dict使用)是否返回到系统,或者它仍然“锁定”,因为它的某些部分仍然被second_book
引用?
1条答案
按热度按时间5f0d552i1#
这是一个具有引用计数的对象集合。当计数为零时-或者当垃圾收集器检测到只剩下循环引用时-任何给定的对象都将被删除并返回到 *python的 * 内存池。
当您创建
outer
时,您创建了一组对象,它们都有一个引用。outer['books'][1]
只有一个引用,这是因为它所在的列表。second_book = outer['books'][1]
向该对象添加了一个引用,现在它有两个引用,但其他对象仍然只有1个引用。del outer
并没有真正删除任何东西-它减少了引用计数。外部列表开始删除(即减少引用计数)其内容。如果一个项也是一个容器,则该删除将继续向下传播。所以每个人的裁判数都减1。除了有2个ref计数的对象之外,所有对象都将被删除,因为它们的计数将变为零。请注意,这发生在
del
操作期间。您不需要垃圾收集器来完成此操作。当存在循环引用时,需要GC。假设这些内部dicts也有一个引用外部dicts的键。你就有麻烦了。一般来说,对象不会更改它们的ID/地址。如果发生这种情况,它是一个新的对象。诸如
+=
之类的增强操作可以创建新对象。比如说int
对象的增强add创建了一个新对象1001
并将其分配给foo
。bar
仍然有对1000的引用,因此不会被删除。看起来好像foo
中的对象更改了地址,但实际上创建了一个新对象。这里,
list
对象的增广加法扩展了foo
中的现有列表,因此foo
和bar
仍然引用相同的内存。