Android NDK переполняет dlvik локальную справочную таблицу JNI
У меня есть следующая проблема: из С++ я посылаю огромную строку [] в java. Огромное = не более 20 строк;
Я делаю следующее
jint jtype = 2;
jstring emptyString = env->NewStringUTF("");
jobjectArray data = (jobjectArray)env->NewObjectArray(7, env->FindClass("java/lang/String"), emptyString);
env->SetObjectArrayElement( data,0,env->NewStringUTF(item->get_id().c_str());
env->SetObjectArrayElement( data,1,env->NewStringUTF(item->get_number().c_str());
env->SetObjectArrayElement( data,2,env->NewStringUTF(item->get_fullname().c_str());
env->SetObjectArrayElement( data,3,env->NewStringUTF(item->get_mf().c_str());
env->SetObjectArrayElement( data,4,env->NewStringUTF(item->get_dob().c_str());
env->CallVoidMethod(dao, jsaveItem, data, jtype);
int i;
for (i = 0; i < 5; ++i) {
jstring string = (jstring) env->GetObjectArrayElement(data, i);
env->DeleteLocalRef(string);
}
env->DeleteLocalRef(emptyString);
env->DeleteLocalRef(data);
env->DeleteLocalRef(dao);
это происходит в цикле, поэтому я делаю это для каждого объекта, который я хочу сохранить в базе данных, так что вы можете себе представить, что это происходит много раз.
Итак, я считаю, что VM и удаляет локальные ссылки каждой строки, которую я создаю, но все же получаю:
ReferenceTable overflow (max=512)
Last 10 entries in JNI local reference table:
502: 0x40552880 cls=Ljava/lang/String; (28 bytes)
503: 0x405528b8 cls=Ljava/lang/String; (28 bytes)
504: 0x4051f8d0 cls=Ljava/lang/Class; 'Lcom/project/storage/userdata/DataDao;' (212 bytes)
505: 0x4052eb38 cls=Lcom/project/storage/userdata/DataDao; (12 bytes)
506: 0x4051f8d0 cls=Ljava/lang/Class; 'Lcom/project/storage/userdata/DataDao;' (212 bytes)
507: 0x4052eb38 cls=Lcom/project/storage/userdata/DataDao; (12 bytes)
508: 0x4051f8d0 cls=Ljava/lang/Class; 'Lcom/project/storage/userdata/DataDao;' (212 bytes)
509: 0x4052eb38 cls=Lcom/project/storage/userdata/DataDao; (12 bytes)
510: 0x4051f8d0 cls=Ljava/lang/Class; 'Lcom/project/storage/userdata/DataDao;' (212 bytes)
511: 0x4052eb38 cls=Lcom/project/storage/userdata/DataDao; (12 bytes)
JNI local reference table summary (512 entries):
58 of Ljava/lang/Class; 212B (1 unique)
1 of Ljava/lang/Class; 236B
25 of Ljava/lang/Class; 284B (1 unique)
1 of Ljava/lang/Class; 572B
392 of Ljava/lang/String; 28B (392 unique)
1 of Ljava/lang/String; 36B
1 of [Ljava/lang/String; 28B
2 of [Ljava/lang/String; 92B (2 unique)
31 of Lcom/project/storage/userdata/DataDao; 12B (1 unique)
Memory held directly by tracked refs is 12540 bytes
Любые идеи относительно того, почему происходит переполнение?
что я делаю неправильно?
Ответы
Ответ 1
Попробуйте удалить локальные ссылки сразу после использования. Вот так:
jstring string;
string = env->NewStringUTF(item->get_id().c_str());
env->SetObjectArrayElement( data,0,string);
env->DeleteLocalRef(string);
string = env->NewStringUTF(item->get_number().c_str());
env->SetObjectArrayElement( data,1,string);
env->DeleteLocalRef(string);
string = env->NewStringUTF(item->get_fullname().c_str());
env->SetObjectArrayElement( data,2,string);
env->DeleteLocalRef(string);
string = env->NewStringUTF(item->get_mf().c_str());
env->SetObjectArrayElement( data,3,string);
env->DeleteLocalRef(string);
string = env->NewStringUTF(item->get_dob().c_str());
env->SetObjectArrayElement( data,4,string);
env->DeleteLocalRef(string);
env->CallVoidMethod(dao, jsaveItem, data, jtype);
Я не уверен, возвращает ли GetObjectArrayElement() тот же локальный или создаёт новый. Если он создает новый, это объясняет, почему вы заполняете таблицу localref.
Ответ 2
Ответ на @Davids верен. У вас заканчивается место в локальной справочной таблице, поскольку ссылки на временные строки, которые вы создаете с помощью NewStringUTF
, теряются. Если вы посмотрите на свое сообщение об ошибке, вы можете увидеть
392 из Ljava/lang/String; 28B (392 уникальных)
Ссылки Объекты NewStringUTF, которые вы создаете, являются "анонимными" и будут потеряны. Удалив ссылку на data
, вы удаляете ссылку на массив. Строки будут по-прежнему находиться в памяти, пока функция не выйдет. Я также чувствую, что передача emptyString
в качестве аргумента для NewObjectArray
является сверхплотной, а NULL будет делать также