Возвращение массива из JNI в Java вызывает медленную утечку - PullRequest
1 голос
/ 10 октября 2019

У меня есть кеш, реализованный в c ++ с использованием multimap, а затем я просматриваю кеш и возвращаю совпадающие целочисленные значения в виде массива в код Java.

Проблема, с которой я сталкиваюсь, заключается в постепенном старом поколенииполностью заполняется и запускает непрерывный полный GC оттуда. Я обнаружил, что просто возвращение статического массива приводит к тому, что старое поколение периодически заполняется и запускает полный сборщик мусора. В конце концов при высокой нагрузке система будет создавать дамп памяти.

Код похож на Java

for(JavaObject o: javaOjctes){
     int[] values = cache.get(o.getkey1,o.getkey2,o.getkeyType[]);
      //further processing
   }

, а на стороне C ++ у меня есть CacheImpl.cpp

JNIEXPORT jintArray JNICALL Java_com_test_cache_CacheService_get(JNIEnv *env, jobject thisObject, jstring key1,jstring key2,jobjectArray keyTypes){

const char *key1Value = (env)->GetStringUTFChars(key1,NULL);
env->ReleaseStringUTFChars(key1,key1Value);
//if(key1Value == NULL)
    //return NULL;

const char *key2Value = (env)->GetStringUTFChars(key2,NULL);

 //if(key2Value == NULL)
     //return NULL;

string key2_str(key2value);
env->ReleaseStringUTFChars(key2,key2Value);


jsize length = env->GetArrayLength(keyTypes);

 if(length == 0)
     return NULL;

// I’m managing the C++ cache from Java side, so getting the
// reference of native cache from Java
jclass CacheService = env->GetObjectClass(thisObject);
Cache* cache= (Cache*) env->GetStaticLongField(CacheService,getCacheField(env,thisObject));
env->DeleteLocalRef(CacheService);
list<int> result;
for(int index=0;index<length;index++){

  jstring keyType =(jstring) env->GetObjectArrayElement(keyTypes,index);
  const char *key_type_str=env->GetStringUTFChars(keyType,NULL);
  string key_type(key_type_str);
  env->ReleaseStringUTFChars(keyType,key_type_str);

   // Cache.cpp code is given below
  list<int> intermediate=cache->get(key2_str+key_type,key1Value);
  result.merge(intermediate);


  intermediate=cache->get(key_type,key1Value);
  result.merge(intermediate);
}

env->ReleaseStringUTFChars(key1,key1Value);

// I would return result list from below code
// For testing I commented all of the above code and
// tested with only below code. I could see Old gen
// Keep growing and GC spikes

    jintArray Ids=env->NewIntArray(50);
          if(Ids == NULL){
              return NULL;
          }
         jint return_Array[50];
         int j=0;
         for(j=0; j<50 ;j++){
            return_Array[j]=j;
          }
          env->SetIntArrayRegion(Ids,0,50,return_Array);
          //env->DeleteLocalRef(Ids);
          return Ids;

иКод Cache.cpp выглядит следующим образом:

shared_ptr<multimap<string, SomeObject> > Cache::cacheMap;

list<int>  Cache::get(string key,const char* key1Value){

       SomeObject value;
       list<int> IDs;

       shared_ptr<multimap<string, SomeObject> > readMap=atomic_load(&cacheMap);
       pair<mapIterator,mapIterator> result=readMap->equal_range(key);

       for(auto iterator=result.first; iterator!=result.second; iterator++){
          value=iterator->second;

          if(!(value.checkID(key1Value))){
              IDs.push_front(value.getID(key1Value));

          }
       }

       return IDs;
}

В приведенном выше коде я предполагаю, что массив Ids

jintArray Ids=env->NewIntArray(50);

не удаляется, поэтому я попытался

//env->DeleteLocalRef(Ids);

Это не работает, поскольку пустой массив будет возвращен на стороне Java.

Как описано в комментариях к коду, я закомментировал весь код, за исключением возврата статического массива в Java. Я мог видеть, что Старое Поколение постепенно заполнялось, вызывая Полный GC, который, я считаю, является проблемой медленной утечки. У меня медленная утечка в этом потоке поиска в кеше. Я что-то пропустил?

Спасибо, Радж

...