微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

从 go 写入 C 内存的正确方法

如何解决从 go 写入 C 内存的正确方法

我想通过导出一些 C API 将 go 程序移植为库。在 C 中,函数接受缓冲区(指针)作为参数(连同其大小)并将输出写入其中是很常见的。 例如(来自 C 标准库)

size_t fread(void *ptr,size_t size,size_t nmemb,FILE *stream);

这将写入调用者指定的 *ptr 最多 size*nmemb 个字节。这种设计的好处是内存由调用者管理,因此函数不需要处理内存分配。我希望从 go 导出的 API 也像这样。

然而,我发现在 go 中没有直接写入指针的方法。所以我创建了这样的东西(对 this documentation 的 case 6 稍作修改),它在 go 中使用 C 的底层内存创建了一个 []byte 对象。

// create a byte array using C memory for internal use
func createBuffer(buf unsafe.Pointer,size int) []byte {
    var res []byte
    hdr := (*reflect.SliceHeader)(unsafe.Pointer(&res))
    hdr.Data = uintptr(unsafe.Pointer(buf))
    hdr.Len = size
    hdr.Cap = size
    return res
}

然后我将我的函数导出如下(readersio.Reader 的一部分,unsafe.Pointer 在导出后将具有 void* 类型),它将读取一些数据到最多提供 size 个字节的 C 内存。

//export read
func read(id int,buf unsafe.Pointer,size C.int) int {
    res,err := readers[id].Read(createBuffer(buf,int(size)))  // works
    //res,err := readers[id].Read(C.GoBytes(buf,size)) // does not work
    if err != nil {
        return -1
    }
    return res
}

这按预期工作(即在我的 C 程序中,调用 read 后缓冲区确实包含所需的数据),但我不确定这是否是正确的方法(即是否有内存问题尤其与垃圾回收 (GC) 相关。

假设从 []byte 返回的结果 createBufferread 终止后没有在其他任何地方使用,GC 将如何释放内存? GC 是否也会尝试释放 hdr.Data,它应该是由 C 程序管理的一块内存? official documentation 对此提供了相当多的警告。如果这会导致 GC 问题,那么正确的方法是什么? (我已经尝试过 C.GoBytes(...),它似乎复制了底层缓冲区,因此不起作用)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。