python 对象清理顺序 - 我可以使用对象引用强制 GC 首先收集另一个对象吗?

问题描述 投票:0回答:1

我有 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 garbage-collection pybind11
1个回答
0
投票

“摧毁”的本意尚不清楚,尽管这不是你的错;-)这是微妙的东西。

对我来说,“销毁”意味着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对象的内部双向链表中。随着时间的推移,该列表会以各种方式进行分区和重新排序,这是运行循环垃圾回收的副作用,并且幸存的对象会被移动到较旧的“世代”。 但是这些“应该”对于正常代码的语义来说并不重要。

© www.soinside.com 2019 - 2024. All rights reserved.