Утечка памяти в полиморфизме SWIG в C ++ и Java с использованием директоров - PullRequest
3 голосов
/ 22 декабря 2011

У меня есть программа на C ++ для получения двоичных данных из сети.После получения данных они будут вызывать данные в виде байтового массива из C ++ для клиента Java.Я использую функцию директора в SWIG, чтобы легко достичь межязыкового полиморфизма в C ++ и Java для обратного вызова.Вот ссылка .

Но я обнаружил, что в SWIG нет типографских карт от char * в C ++ до byte [] в Java.Итак, я добавил патч к virous.i.Вот ссылка .

/*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 никогда не собирает мусор.Метод onDataReceived в сгенерированном SWIG-файле оболочки выглядит следующим образом:

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 через долгое время.Заранее спасибо за любую помощь!

PS.Данные довольно большие, они составляют около 32 КБ.

1 Ответ

2 голосов
/ 23 декабря 2011

Я получил решение, добавив удаление ссылки на jb в картах типов Director: (jenv) -> DeleteLocalRef (jb);

Вот обновленный патч .

...