【发布时间】:2021-05-23 09:55:16
【问题描述】:
Golang
import "C"
//export MyFunction
func MyFunction(str *C.char) *C.char {
goStr := C.GoString(str)
msg := goStr + " world"
return C.CString(msg)
}
func main() {}
Java
public interface MyLib extends Library {
MyLib INSTANCE = Native.load("mylib.so", MyLib.class);
String MyFunction(String str);
}
public class CGoExample {
public static void main(String[] args) {
String str = "Hello";
String msg = MyLib.INSTANCE.MyFunction(str);
System.out.println(msg);
}
}
这段代码有效,Java 字符串被传递给 Go,Go 返回一个新字符串。我遇到的问题是 Go 返回的 CString 不会被 Java 或 Go 垃圾收集器释放。 CGO 文档指出“调用者有责任安排它被释放,例如通过调用 C.free”,当然在我的情况下调用 C.free 将不起作用,因为我正在返回 CString 并且如果我释放返回之前的 CString 我没有从 Go 函数得到正确的响应。我也尝试调用defer C.free(unsafe.Pointer(msg)),但我发现defer 语句将在return 语句之前被调用。
由于我需要返回 CString,我假设它的内存需要从 java 中释放,我该如何做呢?
编辑:
根据 DanielWiddis 的评论,我尝试了以下方法,但 java 进程存在,代码为 -1073741819。
// #include <stdlib.h>
import "C"
import "unsafe"
//export MyFunction
func MyFunction(str *C.char) *C.char {
goStr := C.GoString(str)
msg := goStr + " world"
return C.CString(msg)
}
//export Free
func Free(str *C.char){
C.free(unsafe.Pointer(str))
}
func main() {}
public interface MyLib extends Library {
MyLib INSTANCE = Native.load("mylib.so", MyLib.class);
String MyFunction(String str);
void Free(String str);
}
public class CGoExample {
public static void main(String[] args) {
String str = "Hello";
String msg = MyLib.INSTANCE.MyFunction(str);
System.out.println(msg);
MyLib.INSTANCE.Free(msg);
}
}
【问题讨论】:
-
在旧版本的 Java 中,我可能会为此使用
finalize()方法。但是我认为finalize()现在已弃用,因此您需要做一些额外的工作。或者至少为finalize()被完全删除的那一天做好准备,如果你还不想做这项工作的话。 -
你能不能把
C.free映射为接口中的另一个函数/方法并从Java 调用它?几乎所有其他 API 都是这样做的。 -
理论上,
CString确实会为libc提供的malloc()提供内存,cgo安排与生成的可执行映像链接;C.free是同一个libc到free()的(几乎)一对一映射。因此,技术上您可以在该内存上调用free(),但这必须是相同free()——在某种意义上它必须是由同样libc。我不知道你是否可以用 JNA 保证这一点。如果没有,我同意 Daniel Widdis 的建议。 -
另一种选择是注意到
C.CString(s)没什么特别的(调用malloc()来获得一块长度为len(s)+1的内存,复制s的字节并写入NUL 最后)并向 C 端提供您自己的“分配”和“解除分配”函数,它们的工作方式与malloc()和free()一样,并将由 JNA 部分和 Go 部分共享。然后,Go 部分可以对该分配器函数进行薄包装,该函数将执行C.CString所做的事情:调用分配器,复制内存,写入 NUL。