5

当使用 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);
}

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

4

1 回答 1

3

根据gmp CGo 示例

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

C 世界很难有指向 Go 世界的指针,因为 Go 垃圾收集器不知道 C 分配的内存。最重要的考虑是不限制未来的实现,所以规则是 Go 代码可以将 Go 指针传递给 C 代码,但必须单独安排 Go 保持对指针的引用,直到 C 完成它。

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

希望有帮助。

于 2013-12-04T01:04:12.433 回答