在 Larry Hastings 的 GIL 演讲的这一部分中,解释了 ironclad 如何提供与 IronPython 的 C 扩展兼容性。这是演讲中有趣的部分:
我们实现了一个叫做 Ironclad 的东西,这是一个实现 IronPython 的 Python C-API 和 IronPython 没有 GIL 它不使用引用计数,但我们维护二进制 与现有二进制文件的兼容性。
这些现有的二进制文件所拥有的是 C 对象 (实际上是用 C 实现的 python 对象)期望使用 引用计数所以我们有一个混合系统。对于那些曾经是 从 C 扩展返回,我们人为地夸大了它们的引用 按 1 计数,以便编译到二进制文件中的macros 永远不会因为降到零而被触发,然后我们就有了一个代理 object 如果这个对象进入了垃圾回收,那么我们 会将引用计数减少到零。
从技术上讲,我们存在泄漏,因为如果您传递对 python 反对 C 扩展,C 扩展可以保留 提到那些活着的人,基本上拉里所说的是 如果你转向类似 Mark 的东西并扫描主要的 python C 解释器中,那些 C 对象对于垃圾收集器来说是不透明的。 它无法知道你有什么内部参考。
我的问题:
1- 如果 GC 是在解释器本身(例如 IronPython)中实现的,那么他所指的宏是什么? (我们应该关心这一点并为此增加引用计数!)
2- 代理对象的作用是什么?它是在 C 扩展中实现的 python 对象的代理?为什么我们不直接减少原始对象的引用计数呢?
他所指的宏是在C端使用的Python-C API宏。
代理对象的作用是在CPython的引用计数GC和IronPython的.Net GC之间进行转换。
这是一门高级科目。如果您不熟悉这两个 Python 实现,这些答案可能对您没有帮助。但这里没有简单的答案。
模块可以做任何实际的事情。某些模块在方法/函数调用期间保留对象,例如当计算可能更长时。在普通的Python中。在这种情况下,对象应该向引用计数加一,直到完成为止。
在非常基础的层面上,Python 对象的引用计数是 每当对象被引用时就会递增,并且会递减 当对象被取消引用时。如果一个对象的引用计数为0, 对象的内存被释放。你的程序代码不能 禁用 Python 的引用计数。
例如你有三种方法。
start_calculation(data)
get_finished_calculations()
调用第一个会在某些模块堆栈上设置数据并保留一些Python对象,数据的引用计数应该增加1。当最终由 get_finished_calculations 返回结果时,引用计数将减少。但因为这些堆栈位于 C 模块一侧,在 .Net 术语中被视为非托管代码,垃圾收集器无法看到它,并且即使模块仍然需要进行计算也会删除数据,因为 IronPython 也没有像 CPython 那样的引用计数有。