我最近了解到,当你在 Python 中删除一个列表时,这个列表的引用会保存在一个数组中,并在你初始化一个新列表时弹出。
我在我的常规解释器中运行了这个:
l = [1,2,3]
l_id = id(l)
del l
g = [1,2,3]
id(g) == l_id # True
正如预期的那样,我得到了正确的结果。
我在我的 IPython 解释器上尝试了同样的事情,却得到了 False
。为什么会这样?好点了吗?
Python版本:v3.7.0:1bf9cc5093
Ipython 版本:7.5.0
更新
它也发生在不同的列表中:
l = [1,2,3]
l_id = id(l)
del l
g = [1,2,3,4,5,6,7,8]
id(g) == l_id # True
而且它总是发生,他们得到相同的引用并不是随机的事情
更新2
我知道为什么会这样,我只是想知道为什么它只发生在纯 python 解释器上而不是在我的 ipython 上,以及这些方法中哪一种更适合内存管理
更新 3
因为我可以解释这些列表具有相同 ID 的原因,所以我不明白为什么 ipython 和 Python 之间存在差异。
看List listobject.c的实现.
正如我们所见,有一个引用数组,称为free_list
。其中数组的值是被销毁的列表对象,数组索引的计数numfree
。我们可以看到,如果删除了超过 80 个列表,则下一个列表不会保存在数组中。所以从这些行我们可以说我的陈述对于任何新的 python 解释器都是正确的。
但我仍然找不到让 ipython 像这样工作的原因
最佳答案
首先,id()
与 Python 语言中的一般内存管理没有任何关系。但是,在 CPython(因此是 IPython REPL)中,它与原始内存位置具有一对一的对应关系。一些评论指出,这个问题在抽象上不一定有意义,但仅限于 IPython 和标准 CPython REPL 似乎适用。
所有发生的事情是,在处理您的单元格 block 时,IPython 环境在幕后创建了一些额外的对象(包括列表对象)。由于 l
的原始内存空间被 IPython 在幕后创建的一些列表占用,因此 CPython 分配器为 g
找到了一个新的内存块。
要获得额外对象的一些证据,请考虑以下在 CPython 和 IPython 中运行的内省(introspection)垃圾收集器的实验。
from gc import get_objects
orig = set(map(id, get_objects()))
l = [1,2,3]
l_id = id(l)
del l
g = [1,2,3]
final = set(map(id, get_objects()))
len(orig.symmetric_difference(final)) # 2 in CPython, 6-40+ in IPython
关于python - 为什么在删除列表时 IPython 管理内存的方式与 CPython 不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58087537/