5

当有人从 C 库绑定到 Java(或任何其他没有保证运行的析构函数的垃圾收集语言)时,他们如何处理非垃圾收集内存的正确释放?

编辑:我在想的是(我知道这在我的原始问题中没有明确说明)是当一块非 gc'ed 内存包含对其他非 gc'ed 资源的引用时,这些资源需要被释放对象被释放。例如,如果您有一个未经过 gc 处理的链表节点,它是一长串此类节点的头部,并且您希望 gc 系统最终自动清理它,您如何设置它?

4

3 回答 3

2

它们通常提供 API 来创建和发布引用。

例如,Java 的本机接口提供全局引用,允许将 Java 对象固定在内存中,直到 C 程序通过NewGlobalRefDeleteGlobalRef

NewGlobalRef创建对 obj 参数引用的对象的新全局引用。obj 参数可以是全局或局部引用。全局引用必须通过调用显式处理DeleteGlobalRef()

它还提供本地引用,只要 Java 将控制权交给 C 就可以持续:

本地引用在本机方法调用期间有效。在本机方法返回后,它们会自动释放。

JVM 嵌入 API提供了一种类似的机制,它允许将对象固定在内存中,直到 C 程序确定它已完成。

Python 的 C 扩展 API提供了与 JNI 类似的 API。

通过调用 可以将借用的引用更改为拥有的引用Py_INCREF()

引用的所有者负责Py_DECREF()在不再需要引用时调用。

python 名称反映了 python 使用引用计数 * 但 API 与基于非引用计数垃圾收集器的 JNI 中的 API 基本相同的事实——您有一个函数可以固定由解释器管理的内存区域一个将先前固定的区域释放回解释器。

* - python 不是真正的引用计数方法。来自同一页面“虽然 Python 使用传统的引用计数实现,但它还提供了一个循环检测器,用于检测引用循环。”

于 2011-08-03T17:11:32.220 回答
2

在 java 中,您有finalize()概念。您可以在那里释放 C 内存。

但是,可能更好的方法是将PhantomReferencesReferenceQueue一起使用。您可以扩展 PhantomReference 类,以便它包含一些 id 或指针或任何您需要释放的 C 端内存。当它在 ReferenceQueue 中排队时,您可以释放此 id 指向的 C 端内存 - Java 对象保证不再“在 Java 中”存在。

于 2011-08-03T17:45:22.063 回答
0

当使用 Java 等语言的绑定时,其他语言机器为每个分配的对象保存引用计数器。API 应该提供增加或减少这些计数器的方法,以指示您的 C 程序持有对其他机器对象的引用的机器。如果 C 程序没有对给定对象的引用,则引用计数器可能会达到 0,而其他语言机器将可以自由地对它进行垃圾收集。但是,您可能无法要求机器释放给定对象。

于 2011-08-03T17:06:37.493 回答