我有 2 个对象
a, b
(分别是 A,B
的实例)是在我的应用程序中创建的:
class A:
def __del__(self):
print("A.__del__")
class B:
def __del__(self):
print("B.__del__")
a = A()
b = B()
这将打印出来(在我的机器上:)):
A.__del__
B.__del__
这意味着,在这种情况下,垃圾收集顺序就是创建顺序。
我需要的是强制垃圾收集顺序,以便
a
会在b
之后被销毁。我尝试将 a
保留在 b
内:
b._guard = a
但这并没有帮助,
a
首先被销毁(至少__del__
函数以相同的顺序被调用)。
我的现实世界案例是使用
pybind11
,其中祖父母创建一个父母,然后创建一个孩子,并且该孩子必须在祖父母之前被销毁。将祖父母的 self
保留在孩子体内似乎可行,但在这个简单的情况下,我明确要求它不行,所以我认为这不是一个可靠的解决方案。
如果我的案件是父母和孩子,那么
py::keep_alive
可能对我有帮助,但由于祖父母和孩子之间没有联系,我认为这无关紧要。
是否有一种纯粹的Python方式(或一种简洁的
pybind11
方式)来强制祖父母保持活着直到孩子被清理干净?
“摧毁”的本意尚不清楚,尽管这不是你的错;-)这是微妙的东西。
对我来说,“销毁”意味着Python释放底层内存,因此将来对它的任何引用都可能导致段错误。但这显然不是调用
__del__()
的意思。 __del__
只是另一个 Python 级别的函数,如果它 考虑释放
x.__del__()
的内存,实现将(可能)调用 x
。
是否继续释放内存取决于
__del__()
做了什么。经典例子:
some_global_list = []
def __del__(self):
some_global_list.append(self)
在这种情况下,
self
的内存不会被释放。 self
通过将自身附加到全局列表来“复活”自身(或以任何其他方式使 self
再次“从外部”可访问)。
只要有任何可能的方法可以再次访问对象的内存,Python 就永远不会释放内存。特别是,在循环垃圾回收的情况下,在释放循环对象中的“任何”内存之前,会调用“所有”“析构函数”。因此,在释放任何内存之前,您可能会看到一百万行“__del__
被调用”输出。事实上,如果任何 __del__()
方法恢复了循环,则可能不会释放任何内存。
确切地指定你想要阻止的是什么。一般来说,不,没有办法强制释放内存的顺序。没有定义
“垃圾收集顺序”。在简单的情况下,“创建时间顺序”可能看起来就是这种情况,只是因为顺序对象恰好被添加到可GC对象的内部双向链表中。随着时间的推移,该列表会以各种方式进行分区和重新排序,这是运行循环垃圾回收的副作用,并且幸存的对象会被移动到较旧的“世代”。 但是这些“应该”对于正常代码的语义来说并不重要。