2012-06-18 9 views
14

Tengo el siguiente problema, desde C++ envío una gran cadena [] a java. enorme = como máximo 20 filas; que estoy haciendo lo siguienteAndroid NDK desborda dalvik JNI tabla de referencia local

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); 

esto está sucediendo en un bucle por lo que estoy haciendo por todos los objetos que quiero guardar en la base de datos, así como se puede imaginar, happends un montón de veces.

Así Soy considerado de la máquina virtual y borrar los árbitros locales de cada cuerda creo, pero aún así me sale:

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 

¿Alguna idea de por qué el desbordamiento está sucediendo? ¿Qué estoy haciendo mal?

+0

Estoy bastante convencido de que debes llamar 'ReleaseStringUTFChars' para cada' NewStringUTF', independientemente de si haces 'DeleteLocalRef' después. –

+0

¿Tiene sentido? dado que no estoy accediendo a jstring desde el vm pero enviando uno a él ... ¿Tendría que crear un puntero a la cadena y luego llamar usar ese puntero para hacer el releaseStringUtfChars ... – Tancho

+2

Solo necesita llamar a 'ReleaseStringUTFChars() 'si previamente llamó' GetStringUTFChars() 'para crear una C-String a partir de una Java-String. Ese no es el caso aquí. –

Respuesta

24

Intente eliminar las referencias locales inmediatamente después de su uso. De esta manera:

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); 

No estoy seguro de si GetObjectArrayElement() devuelve el mismo localref o crear una nueva. Si está creando uno nuevo, entonces eso explicaría por qué está llenando la tabla de referencia local.

+0

No veo cómo el sistema puede obtener una nueva referencia? ¿crees que por getElementObject devuelven una copia del puntero? no el original? – Tancho

+0

Sí, devuelve una copia del puntero (en realidad no es solo un puntero, es un reflujo local). Ver la respuesta de @ jogabonito para más detalles. –

+0

¡Funciona como un amuleto, realmente gracias! –

3

@ La respuesta de Davids es correcta. Se está quedando sin espacio en la tabla de referencia local ya que las referencias a las cadenas temporales que está creando usando NewStringUTF se están perdiendo. Si nos fijamos en su mensaje de error, puede ver

392 de Ljava/lang/String; 28B (392 único)

Las referencias de los objetos NewStringUTF que está creando son "anónimos" y se perderán. Al eliminar la referencia a data, solo está borrando la referencia a la matriz. Las cadenas aún estarán en la memoria hasta que la función finalice. También creo que pasar emptyString como argumento a NewObjectArray es superfloo y NULL también lo hará

+0

Bien, ¡pruébalo hoy y comparte resultados después! – Tancho