英文:
cgo pointer value changed
问题
我使用cgo为C API(bullet物理引擎)创建了绑定,其中一些函数使用数据指针。我的想法是,我可以将一个指针附加到一个对象上,并在物理引擎调用回调时稍后检索它。我的问题是,当我收到值后,它发生了变化,而我并没有这样做。似乎没有源代码明确地更改该值。
CollisionObject:源代码,头文件,与该类交互的Go代码
这是我发送值的方式,重新转换为*int和int是正确的,正确的数字被打印出来:
num := x*amounty*amountz + y*amountz + z + 1
ptr := unsafe.Pointer(&num)
fmt.Printf("created %v %v\n", ptr, *(*int)(ptr))
rb := sphere.RigidBody(ptr, 1)
但是当我从raytest中获取它时,值发生了变化:
ptr := hit.GetUserPointer()
log.Printf("we got back: %v %v", ptr, *(*int)(ptr))
指针值本身没有改变,我可以查找并看到有一个指针指向这个位置,但它指向的值是不同的。
现在我想知道,也许Go没有清除该值(垃圾回收),因为它不再使用,并用其他东西替换了这个内存位置。
示例输出(删除了垃圾值):
created: 0xc2080006e0 40
2014/11/07 17:10:01 we got back: 0xc2080006e0 4921947622888946315
非常感谢您的任何指针(哈哈)!
英文:
I made bindings to a C api (bullet physics engine) using cgo, some functions make use of data pointers. The idea is that I can attach a pointer to an object and retrieve it later when the physics engine invokes a callback. My problem is that when i get the value back, it change and I didn't do it. It seems that no source code is explicitelly changing the value.
CollisionObject: source, header,
The go codes that interracts with that class
heres how i send the values, the reconversion to *int and int is fine, the correct numbers are printed:
num := x*amounty*amountz + y*amountz + z + 1
ptr := unsafe.Pointer(&num)
fmt.Printf("created %v %v\n", ptr, *(*int)(ptr))
rb := sphere.RigidBody(ptr, 1)
But when I get it back from a raytest the value changed:
ptr := hit.GetUserPointer()
log.Printf("we got back: %v %v", ptr, *(*int)(ptr))
the pointer value itself didnt change, i can look up and see that there was a pointer pointing to this location, but the value its pointing at is different.
Now i'm wondering if maybe go didn't clean the value (garbage collected) since it wouldn't be used anymore and replaced this memory location with something else.
example output (with junk values removed):
created: 0xc2080006e0 40
2014/11/07 17:10:01 we got back: 0xc2080006e0 4921947622888946315
ANY pointer (hehe) is appreciated
答案1
得分: 1
Go的垃圾回收器不知道由C或C++代码持有的指针,所以没有任何东西可以保持num
变量的存活。
你可以通过在Go变量中存储指针的第二个副本来解决这个问题。一种方法是使用一个类型为map[*C.some_c_type]*int
或类似类型的全局变量,并在其中存储&num
。记得用互斥锁保护这个map,以便在并发访问时行为正确。
为了避免泄漏,当底层C代码不再持有对&num
的引用时,你需要手动从map中删除&num
。如果C库提供了在存储用户指针时设置销毁通知函数的能力,这将很容易实现:只需将一个Go函数导出给C,并将其用作通知函数。如果没有提供这个功能,但是Go绑定知道何时完成指针的使用(例如,如果RigidBody
变量总是通过Go API释放),你可以在那里进行清理。
英文:
Go's garbage collector doesn't know about the pointers held by C or C++ code, so there is nothing to keep the num
variable alive.
You can work around this by storing a second copy of the pointer in a Go variable. One way is to use a global variable with a type like map[*C.some_c_type]*int
or similar, and store &num
there too. Remember to protect the map with a mutex so things behave correctly when you have concurrent access.
In order not to leak, you will need to manually delete &num
from the map when the underlying C code is no longer holding a reference to it. If the C library provides the ability to set a destroy notify function when storing the user pointer, this will be easy: just export a Go function to C and use it as the notify function. If it doesn't, but the Go binding knows when the the pointer will be finished with (e.g. if the RigidBody
variable is always freed via the Go API, you can do the clean up there.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论