Understanding go references in C

polaris · · 558 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>Hi, I&#39;m playing around with exposing some Go struct in C (well Python really via ctypes) and I&#39;m wondering my my struct isn&#39;t being deallocated correctly. I&#39;m expecting that when I call dealloc in Python in the following that the struct is derefenced then garbage collected but that doesn&#39;t seem to be the case. Can anyone tell me why or point me towards reading a better understansing of this?</p> <pre><code>package main import &#34;C&#34; import ( &#34;fmt&#34; &#34;unsafe&#34; ) //Table type for foo type Table struct { name string } //export tableNew func tableNew() unsafe.Pointer { return unsafe.Pointer(&amp;Table{&#34;Lala&#34;}) } //export tableDealloc func tableDealloc(table unsafe.Pointer) { t := *((*Table)(table)) fmt.Println(t.name) } func main() {} </code></pre> <p>Which is compiled with:</p> <pre><code>go build -buildmode=c-shared -o foo.so foo.go </code></pre> <p>And used in Python with:</p> <pre><code>from ctypes import cdll import ctypes qt = cdll.LoadLibrary(&#39;foo.so&#39;) qt.tableNew.argtypes = [] qt.tableNew.restype = ctypes.c_void_p // void pointer qt.tableDealloc.argtypes = [ctypes.c_void_p] qt.tableDealloc.restype = None a = qt.tableNew() qt.tableDealloc(a) &gt; &#39;Lala&#39; qt.tableDealloc(a) &gt; &#39;Lala&#39; </code></pre> <p>As you can see I can call dealloc multiple times where I would expect a second call to trigger a segmentation fault or something.</p> <p>Any thoughts?</p> <hr/>**评论:**<br/><br/>lunixbochs: <pre><p>The Go garbage collector doesn&#39;t track pointers passed to the C world (because that would be absurd). Your dealloc function is a no-op.</p> <p>This is especially true in Go 1.6 which can <em>move</em> pointers without telling you and will likely throw errors about your code above.</p> <p>The Go recommended way of keeping objects alive while allowing reference passing to C-land is to store a copy of the object in a map and delete it from the map to &#34;deallocate it&#34; (which the GC will do on its own time).</p> <pre><code>var tableRef = make(map[uintptr]*Table) //export tableNew func tableNew() C.uintptr_t { table := &amp;Table{&#34;Lala&#34;} utable := C.uintptr_t(uintptr(unsafe.Pointer(table))) tableRef[utable] = table return utable } //export tableDealloc func tableDealloc(ptr C.uintptr_t) { if table, ok := tableRef[ptr]; ok { fmt.Println(table.name) delete(tableRef[ptr]) } } </code></pre></pre>proudstar_: <pre><p>Thanks for the answer. Are there any implications of converting a uintptr to a c void pointer like this? Is there a more appropriate type in C?</p></pre>lunixbochs: <pre><p>The equivalent type in C is <code>uintptr_t</code>. It&#39;s just a number value that&#39;s guaranteed to be large enough to hold a pointer. You should be able to return this from a Go function using <code>C.uintptr_t</code>.</p> <p>I also forgot you need to call <code>uintptr(unsafe.Pointer(obj))</code> instead of just <code>uintptr(obj)</code>. I&#39;ve updated the original comment.</p></pre>: <pre><p>[deleted]</p></pre>proudstar_: <pre><p>I was hoping that by dereferncing the pointer in dealloc I would trigger Go garbage collector to free the memory.</p> <p>Is there a way to force this?</p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

558 次点击  
加入收藏 微博
0 回复
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传