将数组从JNI返回到Java导致缓慢泄漏 我使用C++实现了使用MultMAP的缓存,然后查找缓存并将匹配的整数值返回到java代码。
我面临的问题是,旧一代逐渐变得完全满了,并从其上触发连续的完全GC。我发现,仅仅返回一个静态数组就会导致旧一代周期性地填充并触发一个完整的GC。最终,在高负载时,系统将堆转储 代码如下所示 爪哇将数组从JNI返回到Java导致缓慢泄漏 我使用C++实现了使用MultMAP的缓存,然后查找缓存并将匹配的整数值返回到java代码。,java,c++,memory-leaks,java-native-interface,heap-memory,Java,C++,Memory Leaks,Java Native Interface,Heap Memory,我面临的问题是,旧一代逐渐变得完全满了,并从其上触发连续的完全GC。我发现,仅仅返回一个静态数组就会导致旧一代周期性地填充并触发一个完整的GC。最终,在高负载时,系统将堆转储 代码如下所示 爪哇 + C++侧,caseIMPL,CPP JNIEXPORT jintArray JNICALL Java_com_test_cache_CacheService_get(JNIEnv *env, jobject thisObject, jstring key1,jstring key2,jobject
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;
未被删除,因此我尝试
//env->DeleteLocalRef(Ids);
这不起作用,因为将在Java端返回空数组
正如代码注释中所描述的,我注释掉了所有代码,除了将静态数组返回给Java。我可以看到老一代正在逐渐被填满,从而触发一个完整的GC,我认为这是一个缓慢的泄漏问题。我在这个缓存查找流中有一个缓慢的泄漏。我错过什么了吗
谢谢,
Raj在所有可能的情况下,您都不会调用
ReleaseStringUTFChars()
。@user207421有3个GetStringUTFChars(),我也有相应的ReleaseStringUTFChars()。我重复。你并不是在所有可能的情况下都这么说。考虑各种早期的回报。@ USER 20721好点,在我的用例中,我总是传递参数,所以它们永远不会是空的。但也会考虑检查这一点。在更新的代码中,在调用<代码> RelaseStutuutufCARS 之后,您一直使用<代码> KE1Value<代码>,这是错误的(指针不再保证是有效的)。对于该字符串,您似乎还有两个调用ReleaseStringUTFChars
。在所有可能的情况下,您都没有调用ReleaseStringUTFChars()
。@user207421有3个GetStringUTFChars(),我也有相应的ReleaseStringUTFChars()。我重复。你并不是在所有可能的情况下都这么说。考虑各种早期的回报。@ USER 20721好点,在我的用例中,我总是传递参数,所以它们永远不会是空的。但也会考虑检查这一点。在更新的代码中,在调用<代码> RelaseStutuutufCARS 之后,您一直使用<代码> KE1Value<代码>,这是错误的(指针不再保证是有效的)。对于该字符串,您似乎还有两个调用ReleaseStringUTFChars
。
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;
}
jintArray Ids=env->NewIntArray(50);
//env->DeleteLocalRef(Ids);