外部函数:谁来释放内存?

3

我正在从Python中调用一个Go函数。该Go函数返回一个字符串,具体而言,是一个GoString,其中字符串本身在Go的一侧分配。

问题

谁负责释放这块内存?


以下是一个非常简化的示例。

Go端:

func Create(optsEncoded string) (res string, serr string) {
    opts := map[string]interface{}{}
    if err := json.Unmarshal([]byte(optsEncoded), &opts); err != nil {
        return "", errWithStack(err)
    }
    options := translateCreateOptions(opts)

    result := ...

    payload, err := json.Marshal(result)
    if err != nil {
        return "", errWithStack(err)
    }
    return string(payload), ""
}

Cython绑定:
cpdef object py_create(object items, bytes options):
    cdef GoString opts = ...
    cdef bytes message

    cdef Create_return result = Create(opts)

    if result.r0.n == 0:
        message = result.r1.p
        raise Exception("Something happened")
    message = result.r0.p
    # Do I need to deallocate result.r0 and result.r1?
    return message.decode("utf-8")
1个回答

4
我认为你不应该将GoString返回给C。因为GoString的内存是由go运行时管理和垃圾回收的。在C环境中使用这个字符串是不可靠的。你应该通过调用cs := C.CString(s)来返回一个CString。C代码所做的内存分配是未知的,无法被Go的内存管理器识别。所以我认为你需要自己决定哪一边释放CString这里这里有更多信息。

哦,太好了。不过我需要先读一下参考文献。第一个链接是 404。 - wvxvw
Morty 是正确的,我同意他们的观点。第一个资源的正确链接是这个。请还阅读这个,以及最重要的这个,特别是其中的“Go references to C”和“Passing pointers”部分。对于真正深入的细节,你可能会发现阅读这个很有启发性。 - kostix
1
另外一点需要注意的是:当在Go中使用CString时,内存将使用与生成Go代码链接的libcC.malloc进行分配。因此,当将此代码与“普通”的C代码或作为Python扩展的C代码组合时,需要做两件事情:1)编译该C代码时将链接相同的libc - 以具有相同的mallocfree实现,2)您的C扩展必须有一种方法来调用未装饰的free释放从Go侧传递的内存(而不是来自任何CPython内存管理代码的某些函数,如果有的话)。 - kostix
1
@kostix提出了关于Go和扩展使用的相同freemalloc的几个非常重要的观点。更多细节是,Python自己的分配器分别称为Py_MallocPy_Free,以避免与libc版本混淆。在Cython代码中,使用from libc.stdlib cimport free, malloc来使用Go通过libc使用的相同函数。 - danny
1
简化此过程的另一种方法是在Cython中将C字符串转换为Python字符串。由于C字符串是通过Go创建的,因此其长度已知,可以加快转换为Python字符串的速度。将其制成Python对象后,可以立即取消分配C字符串,因为它已被复制,而Python字符串留给Python GC处理,因为您无论如何都需要从Python函数返回Python字符串。 - danny

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接