JNA 是不是释放 Go CString 返回值的内存

Posted

技术标签:

【中文标题】JNA 是不是释放 Go CString 返回值的内存【英文标题】:Does JNA free memory of Go CString return valueJNA 是否释放 Go CString 返回值的内存 【发布时间】:2019-11-08 02:02:42 【问题描述】:

我有一个这样的 JNA 接口:


interface JJ 
    String Hello(GoString.ByValue sql);

Go 中对应的原生代码:


//export Hello
func Hello(ss string) *C.char 

    s := ss + " world"
    return C.CString(s)


本机代码返回一个指向字符串的指针。

JNA 代码是否释放本地代码分配的字符串指针? 如果没有,如何释放?

【问题讨论】:

【参考方案1】:

我将回答一般性问题和具体示例。

JNA 不会维护对本机内存的任何引用,除非您自己在 JNA 中分配它(例如,定义一个 byte[] 数组或 Memory 缓冲区,然后将其传递给函数)。在这些情况下,当 Java 对象被垃圾回收时,本机内存会被释放。

如果您没有将任何内存传递给 C 来填充,那么 JNA 不会对本机内存做任何事情,您必须阅读 API 文档以了解您对释放本机字符串的责任.

C++ CString 类型不一定需要被释放unless it is stored in a new object。然而,Go 确实将CString 实现为一个对象,并记录了这些要求。对于您的特定示例,the docs 说:

Go 的内存不知道 C 代码分配的内存 经理。当您使用 C.CString(或任何 C 内存)创建 C 字符串时 分配)你必须记住在完成后释放内存 通过调用 C.free.

来自cgo wiki:

要记住的重要一点是 C.CString() 将分配一个 适当长度的新字符串,并将其返回。这意味着 C 字符串不会被垃圾收集,这取决于您 释放它。以下是执行此操作的标准方法。

// #include <stdlib.h>

import "C"
import "unsafe"
...
    var cmsg *C.char = C.CString("hi")
    defer C.free(unsafe.Pointer(cmsg))
    // do something with the C string

当然,你不需要使用 defer 来调用 C.free()。你可以 随时释放 C 字符串,但您有责任 确保它发生。

【讨论】:

as docs 说 CString 复制并分配了一个需要显式释放的新字符串,因此实际上它没有分配在堆栈上 @pdeva 谢谢,我已经更新了我的答案。我不知道这是否是 Go 的特点。我的回答基于this answer。可能是 Go 内部调用了 new 变体。【参考方案2】:

让 Java 分配缓冲区,以便它会为您释放它。否则您必须自己释放它并导出释放函数..

public interface JJ 
    JJ lib = (JJ)Native.loadLibrary("jj.so", JJ.class);

    void Hello(byte[] sql);


func Hello(ss []byte) 
    copy(ss[:], string(ss) + " world")

用法:

void main(String[] args) 
    byte[] text = new byte[256];

    JJ.lib.Hello(text);

    System.out.println(Native.toString(text));

您可以将整个内容包装到一个通用函数中,该函数将为您为任何给定的本机函数创建一个字符串。但您明白了。

    Java 分配缓冲区,Go-Lang 填充它,Java 自动释放它。 Go-Lang 分配缓冲区,Java 使用它,Go-Lang 释放它。

在这两种情况下,分配缓冲区的人都必须释放它。

【讨论】:

以上是关于JNA 是不是释放 Go CString 返回值的内存的主要内容,如果未能解决你的问题,请参考以下文章

在 C 和 Go 中传递指针而不是返回新变量?

结构 JNA 返回错误值

JNA 调用 SetTcpEntry 总是返回 317

Go语言闭包

GO基础之函数

如何处理以数组作为返回值的 go RPC 调用?