你能用Go语言将一个对象“固定”在内存中吗?

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

Can you "pin" an object in memory with Go?

问题

我有一个Go对象,我希望它在内存中的地址保持不变。在C#中,可以固定对象在内存中的位置。在Go中是否有类似的方法?

英文:

I have a Go object whose address in memory I would like to keep constant. in C# one can pin an object's location in memory. Is there a way to do this in Go?

答案1

得分: 9

你保留引用的对象不会移动。没有句柄或间接引用,你得到的地址是永久的。

根据文档

注意,与C不同,返回局部变量的地址是完全可以的;变量相关的存储在函数返回后仍然存在。

当你设置一个变量时,你可以使用&运算符读取该地址,并且可以传递它。

英文:

An object on which you keep a reference won't move. There is no handle or indirection, and the address you get is permanent.

From the documentation :

> Note that, unlike in C, it's perfectly OK to return the address of a
> local variable; the storage associated with the variable survives
> after the function returns

When you set a variable, you can read this address using the & operator, and you can pass it.

答案2

得分: 2

tl;dr no - 但是除非你想做一些不寻常的事情,否则这并不重要。

值得注意的是,被接受的答案部分是不正确的。

不能保证对象不会被移动 - 无论是在栈上还是在Go堆上 - 但只要你不使用unsafe,这对你来说并不重要,因为Go运行时会负责透明地更新你的指针,以防对象被移动。

然而,如果你使用unsafe来获取uintptr,调用原始系统调用,执行CGO调用,或以其他方式暴露地址(例如oldAddr := fmt.Sprintf("%p", &foo)),等等,你应该意识到地址可能会改变,编译器和运行时都不会自动修复这些问题。

虽然目前标准的Go编译器只会在栈上移动对象(例如当goroutine栈需要调整大小时),但是Go语言规范中没有阻止不同实现在Go堆上移动对象的内容。

虽然目前(尚未)没有明确支持在栈或Go堆中固定对象的功能,但有一种推荐的解决方法:手动在Go堆之外分配内存(例如通过mmap),并使用finalizers在所有对它的引用都被丢弃后自动释放该分配。这种方法的好处是,在Go堆之外手动分配的内存永远不会被Go运行时移动,因此其地址永远不会改变,但是当不再需要时,它仍然会被自动释放,因此不会泄漏。

英文:

tl;dr no - but it does not matter unless you're trying to do something unusual.

Worth noting that the accepted answer is partially incorrect.

There is no guarantee that objects are not moved - either on the stack or on the Go heap - but as long as you don't use unsafe this will not matter to you because the Go runtime will take care of transparently updating your pointers in case an object is moved.

If OTOH you use unsafe to obtain a uintptr, invoke raw syscalls, perform CGO calls, or otherwise expose the address (e.g. oldAddr := fmt.Sprintf("%p", &foo)), etc. you should be aware that addresses can change, and that nor compiler nor runtime will magically patch things for you.

While currently the standard Go compiler only moves objects on the stack (e.g. when a goroutine stack needs to be resized), there is nothing in the Go language specification that prevents a different implementation from moving objects on the Go heap.

While there is (yet) no explicit support for pinning objects in the stack or in the Go heap, there is a recommended workaround: allocate manually the memory outside of the Go heap (e.g. via mmap) and using finalizers to automatically free that allocation once all references to it are dropped. The benefit of this approach is that memory allocated manually outside of the Go heap will never be moved by the Go runtime, so its address will never change, but it will still be deallocated automatically when it's not needed anymore, so it can't leak.

huangapple
  • 本文由 发表于 2012年8月24日 03:07:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/12098435.html
匿名

发表评论

匿名网友

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

确定