猿问

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

戈朗



import "C"


//export MyFunction

func MyFunction(str *C.char) *C.char {

    goStr := C.GoString(str)

    msg := goStr + " world"

    return C.CString(msg)

}


func main() {}

爪哇岛



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之前释放CString,我不会从Go函数中获得正确的响应。我也尝试过调用,但我发现在返回语句之前将调用延迟语句的困难方式。defer C.free(unsafe.Pointer(msg))


由于我需要返回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);

    }


}


慕运维8079593
浏览 190回答 2
2回答

慕桂英4014372

的返回类型是指针:。C.CString()*C.char通过将其直接映射到 Java 端的 a,您将失去对该本机指针的跟踪,从而无法在以后跟踪和释放它。String最直接的解决方案是将其映射到Java端。在界面中:PointerPointer 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[]class CStringPtr extends PointerType {&nbsp; &nbsp; public CStringPtr(String str) {&nbsp; &nbsp; &nbsp; &nbsp; super(MyLib.INSTANCE.MyFunction(str));&nbsp; &nbsp; }&nbsp; &nbsp; public String getString() {&nbsp; &nbsp; &nbsp; &nbsp; return this.getPointer().getString(0);&nbsp; &nbsp; }&nbsp; &nbsp; public void free() {&nbsp; &nbsp; &nbsp; &nbsp; MyLib.INSTANCE.Free(this.getPointer());&nbsp; &nbsp; }}这将使你的代码:CStringPtr pMsg = new CStringPtr(str);System.out.println(pMsg.getString());pMsg.free();

肥皂起泡泡

根据DanielWiddis的评论,我想出了以下解决方案,该解决方案可以成功为所有涉及的对象分配内存。package main// #include <stdlib.h>import "C"import (&nbsp; &nbsp; "unsafe")//export MyFunctionfunc MyFunction(cStr *C.char) *C.char {&nbsp; &nbsp; str := C.GoString(cStr)&nbsp; &nbsp; msg := str + " world"&nbsp; &nbsp; return C.CString(msg)}//export Freefunc Free(str *C.char){&nbsp; &nbsp; C.free(unsafe.Pointer(str))}func main() {}public interface MyLib extends Library {&nbsp; &nbsp; MyLib INSTANCE = Native.load("mylib.so", MyLib.class);&nbsp; &nbsp; Pointer MyFunction(Pointer ptr);&nbsp; &nbsp; void Free(Pointer ptr);}public class CGoExample {&nbsp; &nbsp; public static void main(String[] args) {&nbsp; &nbsp; &nbsp; &nbsp; // Create pointer with a String value&nbsp; &nbsp; &nbsp; &nbsp; String str = "Hello";&nbsp; &nbsp; &nbsp; &nbsp; Pointer ptr = new Memory(str.length() + 1);&nbsp; &nbsp; &nbsp; &nbsp; ptr.clear();&nbsp; &nbsp; &nbsp; &nbsp; ptr.setString(0, str);&nbsp; &nbsp; &nbsp; &nbsp; //Pass the pointer to Go function which returns the pointer of the message&nbsp; &nbsp; &nbsp; &nbsp; Pointer resultPtr = MyLib.INSTANCE.MyFunction(ptr);&nbsp; &nbsp; &nbsp; &nbsp; //Get the message String from the pointer&nbsp; &nbsp; &nbsp; &nbsp; String msg = resultPtr.getString(0);&nbsp; &nbsp; &nbsp; &nbsp; //Deallocate the memory for the message&nbsp; &nbsp; &nbsp; &nbsp; MyLib.INSTANCE.Free(resultPtr);&nbsp; &nbsp; &nbsp; &nbsp; System.out.println(msg);&nbsp; &nbsp; }}
随时随地看视频慕课网APP

相关分类

Go
我要回答