使用指示器的c++和Java之间SWIG多态性中的内存泄漏

Memory leak in SWIG polymorphism across C++ and Java using directors

本文关键字:多态性 SWIG 之间 内存 泄漏 Java 指示器 c++      更新时间:2023-10-16

我有一个c++程序从网络接收二进制数据。接收到数据后,它将把数据作为字节数组从c++回调到Java客户机。我使用SWIG中的director特性来轻松实现跨c++和Java的跨语言多态回调。这是一个链接。

但是我发现在SWIG中没有从c++中的char*到Java中的byte[]的类型映射。所以我给病毒加了补丁。这是一个链接。

/*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-ed。提前感谢任何帮助!

p。数据相当大,大约32KB。

我通过在Director typemaps中添加对jb的引用的删除来解决这个问题:(jenv)->DeleteLocalRef(jb);

更新后的补丁