如何从 cgo 返回的 C 字符串中释放 java 中的内存(使用 jna)?
How do you deallocate memory in java (using jna) from a C String returned from cgo?
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 return 是一个新字符串。我遇到的问题是 Go 编辑的 CString return 不会被 Java 或 Go 垃圾收集器释放。 CGO 文档指出“调用者有责任安排它被释放,例如通过调用 C.free”,当然在我的情况下调用 C.free 将不起作用,因为我是 returning CString,如果我在 returning 之前释放 CString,我不会从 Go 函数得到正确的响应。我也试过调用 defer C.free(unsafe.Pointer(msg))
但我发现延迟语句将在 return 语句之前调用。
因为我需要 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);
}
}
C.CString()
的return类型是指针:*C.char
.
通过将其直接映射到 Java 端的 String
,您将失去对本机指针的跟踪,从而无法在以后跟踪和释放它。
最直接的解决方案就是将其映射到 Java 端的 Pointer
。在界面中:
Pointer MyFunction(String str);
void Free(Pointer str);
然后使用它:
Pointer pMsg = MyLib.INSTANCE.MyFunction(str);
System.out.println(pMsg.getString(0));
MyLib.INSTANCE.Free(pMsg);
byte[]
个(8 位)字符数组也可能适用于这种情况。就个人而言,我可能会使用类型安全指针和一些面向对象的辅助方法,例如:
class CStringPtr extends PointerType {
public CStringPtr(String str) {
super(MyLib.INSTANCE.MyFunction(str));
}
public String getString() {
return this.getPointer().getString(0);
}
public void free() {
MyLib.INSTANCE.Free(this.getPointer());
}
}
这将使您的代码:
CStringPtr pMsg = new CStringPtr(str);
System.out.println(pMsg.getString());
pMsg.free();
根据 DanielWiddis 的评论,我提出了以下解决方案,它成功地为所有相关对象解除了内存分配。
package main
// #include <stdlib.h>
import "C"
import (
"unsafe"
)
//export MyFunction
func MyFunction(cStr *C.char) *C.char {
str := C.GoString(cStr)
msg := str + " 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);
Pointer MyFunction(Pointer ptr);
void Free(Pointer ptr);
}
public class CGoExample {
public static void main(String[] args) {
// Create pointer with a String value
String str = "Hello";
Pointer ptr = new Memory(str.length() + 1);
ptr.clear();
ptr.setString(0, str);
//Pass the pointer to Go function which returns the pointer of the message
Pointer resultPtr = MyLib.INSTANCE.MyFunction(ptr);
//Get the message String from the pointer
String msg = resultPtr.getString(0);
//Deallocate the memory for the message
MyLib.INSTANCE.Free(resultPtr);
System.out.println(msg);
}
}
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 return 是一个新字符串。我遇到的问题是 Go 编辑的 CString return 不会被 Java 或 Go 垃圾收集器释放。 CGO 文档指出“调用者有责任安排它被释放,例如通过调用 C.free”,当然在我的情况下调用 C.free 将不起作用,因为我是 returning CString,如果我在 returning 之前释放 CString,我不会从 Go 函数得到正确的响应。我也试过调用 defer C.free(unsafe.Pointer(msg))
但我发现延迟语句将在 return 语句之前调用。
因为我需要 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);
}
}
C.CString()
的return类型是指针:*C.char
.
通过将其直接映射到 Java 端的 String
,您将失去对本机指针的跟踪,从而无法在以后跟踪和释放它。
最直接的解决方案就是将其映射到 Java 端的 Pointer
。在界面中:
Pointer MyFunction(String str);
void Free(Pointer str);
然后使用它:
Pointer pMsg = MyLib.INSTANCE.MyFunction(str);
System.out.println(pMsg.getString(0));
MyLib.INSTANCE.Free(pMsg);
byte[]
个(8 位)字符数组也可能适用于这种情况。就个人而言,我可能会使用类型安全指针和一些面向对象的辅助方法,例如:
class CStringPtr extends PointerType {
public CStringPtr(String str) {
super(MyLib.INSTANCE.MyFunction(str));
}
public String getString() {
return this.getPointer().getString(0);
}
public void free() {
MyLib.INSTANCE.Free(this.getPointer());
}
}
这将使您的代码:
CStringPtr pMsg = new CStringPtr(str);
System.out.println(pMsg.getString());
pMsg.free();
根据 DanielWiddis 的评论,我提出了以下解决方案,它成功地为所有相关对象解除了内存分配。
package main
// #include <stdlib.h>
import "C"
import (
"unsafe"
)
//export MyFunction
func MyFunction(cStr *C.char) *C.char {
str := C.GoString(cStr)
msg := str + " 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);
Pointer MyFunction(Pointer ptr);
void Free(Pointer ptr);
}
public class CGoExample {
public static void main(String[] args) {
// Create pointer with a String value
String str = "Hello";
Pointer ptr = new Memory(str.length() + 1);
ptr.clear();
ptr.setString(0, str);
//Pass the pointer to Go function which returns the pointer of the message
Pointer resultPtr = MyLib.INSTANCE.MyFunction(ptr);
//Get the message String from the pointer
String msg = resultPtr.getString(0);
//Deallocate the memory for the message
MyLib.INSTANCE.Free(resultPtr);
System.out.println(msg);
}
}