ネットワークからバイナリデータを受け取るC++プログラムがあります。データが受信されると、C++からJavaクライアントへのバイト配列としてデータがコールバックされます。 SWIGのディレクター機能を使用して、コールバックのためにC++とJavaのクロス言語多型を簡単に実現します。ここにはa linkがあります。ディレクタを使用したC++とJava間のSWIG多型のメモリリーク
しかし、SWIGにchar *からJavaのbyte []にtypemapsはありません。そこで、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"
たとえば、私はJavaコードでバイト配列を受け取ることができます
class B extends A {
@Override
public void onDataReceived(byte[] data, long len) {
//handling the data.
}
}
が、それはそれを思わ:
class A{
public:
virtual void onDataReceived(const char* BYTE, const size_t len) {}
};
を次にJavaコードで、私は拡張するために別のクラスBを持っている:私はC++でクラスが呼び出されJVMによってガベージコレクションされることはありません。 SWIGでonDataReceived方法は、ラッパーファイルを生成し、このようなものです:私のC++コードで
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);
}
コールバックが行われた後、私は受信バッファ内のデータを削除します。しかし、私はJava VisualVMから、Javaクライアントプロセスで使用されているメモリがGC-edでないことを長い間確認しました。助けてくれてありがとう!
PS。データはかなり大きく、約32KBです。
Directorタイプマップのjbへの参照を削除して解決しました。(jenv) - > DeleteLocalRef(jb); – Qinjin
あなたは答えとしてそれを書いて、受け入れられたとマークするべきです。その解決法はコメントとしてしか生きられないほど重要です。 – Flexo