指针在Go语言中由于垃圾回收会改变值吗?

huangapple go评论79阅读模式
英文:

Do pointers change value in Go due to garbage collection?

问题

我是一个相对新手的Go语言开发者。我一直在使用cgo构建与C API的接口,并且经常遇到一个注册回调函数和一个void*类型的cookie参数传递给回调函数的情况。

以下是一段示例代码,展示了我的问题:

/*
void cb(void *cookie) {
   callGo(cookie);
}

go_register_cb(void *ptr) {
   register_cb(&cb, ptr);
}
*/
import "C"

以及

import "C"

//export callGo
func callGo(ptr unsafe.Pointer) {
    x := (*MyStruct)(ptr)
    x.doSomething()
}

func (x *MyStruct) Start() {
    C.go_register_cb(unsafe.Pointer(x))
}

这段代码会导致一个关于Go指针指向Go指针的运行时错误。

我认为我理解了在C语言中保留Go指针的基本含义,即Go垃圾回收器不会考虑C语言中的引用,因此C语言可能会使用一个过时的引用。

我对于不能将包含Go指针的数据结构的Go指针传递给C语言的具体要求感到困惑。我唯一能想到的合理解释是,Go语言中的指针可能会由于垃圾回收而改变值(即它们指向的地址)。这是正确的吗?

英文:

I'm a relative newbie to go. I have been working a lot with cgo and building an interface to a C api. The C api uses a registered callback and a void* cookie parameter to the callback.

Here is some code exemplifying my problem:

/*
void cb(void *cookie) {
   callGo(cookie);
}

go_register_cb(void *ptr) {
   register_cb(&cb, ptr);
}
*/
import "C"

and

import "C"

//export callGo
callGo(ptr unsafe.Pointer) {
    x := (*MyStruct)(ptr)
    x.doSomething()
}

func (x *MyStruct) Start() {
    C.go_register_cb(unsafe.Pointer(x))
}

This code causes a runtime error about Go pointers to Go pointers.

I think I understand the basic implications of keeping Go pointer inside C-land, which is that the C-land reference will not be accounted for in the go garbage collector so C may end up using a stale reference.

The specific requirement that I cannot pass a Go pointer to a data-structure that itself contains a Go pointer is more puzzling. The only thing that makes sense to me is that pointers in Go may change value (that is, the address they point to) due to garbage collection. Is this the case?

答案1

得分: 2

这些关于在Go代码和C代码之间传递指针的规则是在运行时进行动态检查的。所以当你违反这些规则时会出现错误。

而且你的猜测是正确的。由于垃圾回收,地址是可以改变的(指针会被更新)。

来自golang.org的注意事项:

> 即使一个uintptr保存了某个对象的地址,垃圾回收器也不会更新该uintptr的值,也不会阻止该对象被回收。

所以由于垃圾回收,对象的移动是可能的。

英文:

These rules for passing pointer between Go code and C code are dynamically checked at runtime. So when you break them the error occur.

And your guess is right. Addresses are allowed to change due to garbage collection (Pointers are updated).

Note here from golang.org:

> Even if a uintptr holds the address of some object, the garbage
> collector will not update that uintptr's value if the object moves,
> nor will that uintptr keep the object from being reclaimed.

So moving object due to gc is possible.

huangapple
  • 本文由 发表于 2017年2月27日 08:04:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/42475828.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定