我有一个C ++程序来接收来自网络的二进制数据。收到数据后,它会将数据作为字节数组从C ++回调到Java客户端。我使用SWIG中的director功能轻松实现跨C ++和Java的跨语言多态性以进行回调。这是a link。
但是我发现SWIG中没有从C ++中的char *到Java中的byte []的类型映射。所以,我在virous.i上添加了一个补丁。这是a link。
/*Director specific typemaps*/
%typemap(directorin, descriptor="[B") char *BYTE {
jbyteArray jb = (jenv)->NewByteArray(strlen(BYTE));
(jenv)->SetByteArrayRegion(jb, 0, strlen(BYTE), (jbyte*)BYTE);
$input = jb;
}
%typemap(directorout) char *BYTE {
$1 = 0;
if($input){
$result = (char *) jenv->GetByteArrayElements($input, 0);
if(!$1)
return $null;
jenv->ReleaseByteArrayElements($input, $result, 0);
}
}
%typemap(javadirectorin) char *BYTE "$jniinput"
%typemap(javadirectorout) char *BYTE "$javacall"
例如。我在C ++中有一个名为A:
的类class A{
public:
virtual void onDataReceived(const char* BYTE, const size_t len) {}
};
然后在Java代码中我有另一个B类来扩展A:
class B extends A {
@Override
public void onDataReceived(byte[] data, long len) {
//handling the data.
}
}
我可以在Java代码中接收字节数组,但它似乎永远不会被JVM收集。 SWIG生成的包装文件中的onDataReceived方法如下:
void SwigDirector_A::onDataReceived(char const *BYTE, size_t const len) {
JNIEnvWrapper swigjnienv(this);
JNIEnv * jenv = swigjnienv.getJNIEnv();
jobject swigjobj = (jobject) NULL;
jbyteArray jBYTE = 0;
jlong jlen;
if (!swig_override[3]) {
A::onDataReceived(BYTE,len);
return;
}
swigjobj = swig_get_self(jenv);
if (swigjobj && jenv->IsSameObject(swigjobj, NULL) == JNI_FALSE) {
{
jbyteArray jb = (jenv)->NewByteArray(strlen(BYTE));
(jenv)->SetByteArrayRegion(jb, 0, strlen(BYTE), (jbyte*)BYTE);
jBYTE = jb;
}
jlen = (jlong) len;
jenv->CallStaticVoidMethod(Swig::jclass_DataTransferJNI, Swig::director_methids[3], swigjobj, jBYTE, jlen);
if (jenv->ExceptionCheck() == JNI_TRUE) return;
} else {
SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null upcall object");
}
if (swigjobj) jenv->DeleteLocalRef(swigjobj);
}
在我的C ++代码中,我将在回调完成后删除接收缓冲区中的数据。但是我从Java VisualVM检查了很长一段时间后java客户端进程使用的内存不是GC编辑的。感谢您的任何帮助!
PS。数据非常大,大约是32KB。
答案 0 :(得分:2)
我通过在Director类型地图中添加了对jb的引用删除来解决它:(jenv) - > DeleteLocalRef(jb);