需求
java端要调用C++的接口,返回一个byte[]数据。
C++方法定义
DRESULT requestServerRoute(char* bufIn,unsigned int bufLengthIn,char** bufOut,unsigned int* bufLengthOut);
DRESULT releaseServerRouteResult(char* pos);
方法1中,前两参数为输入参数,后两个为输出参数
方法1中为输出的数组申请了内存,方法2为释放此内存的方法,参数为方法1中 char** bufOut的指针
方法一正常调用,接收返回值。
byte[] bufIn = new byte[]{.....};
PointerByReference bufOut = new PointerByReference(Pointer.NULL);
IntByReference bufLengthOut = new IntByReference();
int requestServerRoute(bufIn, bufIn.length,bufOut,bufLengthOut);
byte[] data = bufOut.getValue().getByteArray(0, bufLengthOut.getValue());
问题在方法二,需要传递指向内存地址的指针
尝试1
传入bufOut.getPointer()
long addr1 = VM.current().addressOf(bufOut.getPointer()); //address
尝试2
传入bufOut.getValue()
long addr1 = VM.current().addressOf(bufOut.getValue()); //address
打印地址值和C++申请的地址做比较发现,都不对。。
也不知道jna如何应对这种情况,即将放弃,改用回调方式获取时,看到Pointer的源码中有个属性
/**Pointer value of the real native pointer. Use long to be 64-bit safe.
*/
protected long peer;
找到native pointer后,发现没有获取的方法,翻了一遍还是没找到。又不想写个子类,于是使用源码中的toString获取
public String toString() {
return "native@0x" + Long.toHexString(peer);
}
分别打印
bufOut.getValue().toString();
bufOut.getPoint().toString();
发现getValue()获取的Pointer的peer值和,C++中申请的一致
最后创建
Pointer pointer = Pointer.createConstant(getPeer(bufOut.getValue()));
传入jna方法做为参数,在C++中释放内存。
对JNA不是很熟,还是很多年前用过,所以了解的不多,可能有更好的方法找到的话会贴出来做个记录。
2021-05-24
补充:
以上方式释放内存没有成功,原因不知道。但无意中找到了,获取peer的方式
long peer = Pointer.nativeValue(bufOut.getPointer());
2021-05-25
继续:
尝试使用Native.free在java端释放内存,发现和在C++中释放是一个效果,Native.free后C++会报错 free(): double free detected 说明内存已被释放,但查看系统内存,依然没有变化。。。直到java进程结束才释放掉。继续查找方法
Native.free(peer);
//int releaseResult = releaseServerRouteResult(bufOut.getValue());
2022-09-29
后续使用jdk的监控工具,查看内存非此处占用。可见Native.free(peer)可以成功释放掉 so中申请的内存