繁体   English   中英

如何从 cgo 返回的 C 字符串中释放 java 中的 memory(使用 jna)?

[英]How do you deallocate memory in java (using jna) from a C String returned from cgo?

戈朗


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 function 得到正确的响应。 我也尝试过调用defer C.free(unsafe.Pointer(msg))但我发现在 return 语句之前会调用 defer 语句。

由于我需要返回 CString,我假设它的 memory 需要从 java 中释放,我将如何做 go?

编辑:

根据 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()的返回类型是一个指针: *C.char

通过将其直接映射到 Java 端的String ,您将丢失该本地指针,从而无法在以后跟踪和释放它。

最直接的解决方案就是 map 指向 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);

在这种情况下,(8 位)字符的byte[]数组也可能会起作用。 就个人而言,我可能会使用类型安全指针和一些面向 object 的辅助方法,例如:

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 的评论,我想出了以下解决方案,该解决方案成功地为所有相关对象解除分配 memory。

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);
    }

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM