【问题标题】:Is there a safe way to hold on to a reference to a Go variable from C code using CGo?有没有一种安全的方法可以使用 CGo 从 C 代码中保持对 Go 变量的引用?
【发布时间】:2013-12-20 05:07:55
【问题描述】:

当使用 CGo 将 C 代码与 Go 接口时,如果我在 C 端保留对 Go 变量的引用,我是否会冒该对象被垃圾收集器释放的风险,或者 GC 会看到指针中的指针吗? C端管理的变量?

为了说明我的要求,请考虑以下示例程序:

转码:

package main

/*
typedef struct _Foo Foo;
Foo *foo_new(void);
void foo_send(Foo *foo, int x);
int foo_recv(Foo *foo);
*/
import "C"

//export makeChannel
func makeChannel() chan int {
    return make(chan int, 1)
}

//export sendInt
func sendInt(ch chan int, x int) {
    ch <- x
}

//export recvInt
func recvInt(ch chan int) int {
    return <-ch
}

func main() {
    foo := C.foo_new()
    C.foo_send(foo, 42)
    println(C.foo_recv(foo))
}

C 代码:

#include <stdlib.h>
#include "_cgo_export.h"

struct _Foo {
    GoChan ch;
};

Foo *foo_new(void) {
    Foo *foo = malloc(sizeof(Foo));
    foo->ch = makeChannel();
    return foo;
}

void foo_send(Foo *foo, int x) {
    sendInt(foo->ch, x);
}

int foo_recv(Foo *foo) {
    return recvInt(foo->ch);
}

我是否会冒foo-&gt;chfoo_newfoo_send 调用之间被垃圾收集器释放的风险?如果是这样,有没有办法从 C 端固定 Go 变量,以防止它在我持有对它的引用时被释放?

【问题讨论】:

  • 似乎没有办法阻止 Go 的垃圾收集器,除了关闭它。 blog.golang.org/c-go-cgoMemory allocations made by C code are not known to Go's memory manager. 所以我假设如果你想保留对 Go 的引用,你需要将 Go 值复制到 C 变量中。
  • 博客文章的那部分似乎只是说在 C 中分配的内存不会被 Go 的 GC 释放,这不是我要问的:而不是问Foo 结构,我想知道我存储了一个指针的通道的生命周期是多少。复制变量不是通道之类的选项(出于显而易见的原因)。

标签: garbage-collection go cgo


【解决方案1】:

根据gmp CGo example

垃圾收集是个大问题。围棋世界可以 有指向 C 世界的指针,并在它们出现时释放这些指针 不再需要。为了提供帮助,Go 代码可以定义 Go 对象 持有 C 指针并在这些 Go 对象上使用 runtime.SetFinalizer。

对于 C 世界来说,指向 Go 的指针要困难得多 世界,因为 Go 垃圾收集器不知道内存 由 C 分配。最重要的考虑是不 约束未来的实现,所以规则是 Go 代码可以 将 Go 指针交给 C 代码,但必须单独安排 去挂起对指针的引用,直到 C 完成它。

所以我不确定你是否可以从 C 端固定变量,但你可以通过使用 runtime.SetFinalizer 函数从 Go 端控制变量的垃圾收集。

希望对您有所帮助。

【讨论】:

  • 或者:必须始终从 Go 堆中引用实时 Go 数据,因为这就是 GC 将扫描的全部内容。有时,为了实现这一点,您的 C 可以调用 Go 函数来分配引用持有类型。 (毕竟,只要您的所有引用都在 Go 堆中,就可以了。)其他时候引用来自 malloc 分配的内存,因此您必须编写 malloc/free 包装器或其他东西来人为地创建对来自 Go-land 其他地方的 Go 对象。例如,这些包装器可能是在 map[uintptr]interface{} 中添加/删除条目的 Go 函数。
  • 谢谢。我已经决定在 Go 端管理通道地图:当我想将它们存储在 C 端时添加到地图中,当我想在 C 端释放它们时将它们从地图中删除。跨度>
  • 在一个变量上关闭 GC 后如何手动垃圾收集变量?
猜你喜欢
  • 2017-01-02
  • 2014-03-13
  • 1970-01-01
  • 1970-01-01
  • 2021-06-10
  • 1970-01-01
  • 1970-01-01
  • 2023-03-03
  • 1970-01-01
相关资源
最近更新 更多