2010-12-04 4 views
1

J'ai des problèmes de lecture d'un arraylist d'une classe java avec jni. Dans la classe java ArrayList est défini comme celui-cijvm crash à la lecture arraylist de Java classe avec jni

public static List XTN_STC_search_result = new ArrayList(); 

Le arraylist obtient alors rempli d'une chaîne, une valeur de score en double et un tableau d'entiers. Ainsi la structure ressemble à ceci:

[ 
    [label str 1, score value 1, [int 1, int 2, int n]], 
    [label str 2, score value 2, [int 1, int 2], 
    ... 
]

Du côté JNI C i procédez comme suit pour lire ce arraylist. Après avoir lu le champ statique et obtenu l'objet, je vais dans la boucle en itérant sur le tableau pour lire toutes les valeurs. Tout va bien, je peux lire chaque entrée d'arraylist, la chaîne d'étiquette, la double valeur et peut accéder au tableau d'entiers avec une boucle imbriquée. Dans la boucle imbriquée, si vous récupérez l'entrée du tableau d'entiers avec getObjectArrayElement, il semble obtenir cette valeur. Ensuite, je le tester sur NULL et ce n'est pas NULL. Pour être pédant, je revérifie si cette entrée de tableau (du tableau integer) est une instance de Integer avec isInstanceOf. Cet appel plante mon programme avec SIGSEGV et JVM.

Ci-dessous vous voyez l'extrait de code de la zone problemtic ...

int 
XTN_ce_java_get_cluster(XTN_VM_IDX vm_idx) { 

... 

/* java result object , the arraylist to read */ 
jobjectArray result_obj;  
/* result object array (element of result_obj) */ 
jobjectArray jv_result_object_array;   
jint jv_result_object_array_size; 
/* element to hold phrase, score and nested integer array */ 
jobject jv_object_array_cluster_elem; 
jint jv_object_array_cluster_elem_size; 

... 


/* get arraylist */ 
jv_result_object_array = (*(Record.env))->GetObjectArrayElement(
    Record.env, result_obj, 1); 
jv_result_object_array_size = (*(Record.env))->GetArrayLength(Record.env, 
    jv_result_object_array); 

... 

/* loop over arraylist entries */ 
for (i = 0; i < jv_result_object_array_size; i++) { 

/* read label string */ 
if ((*(Record.env))->IsInstanceOf(Record.env, 
    (jobject)jv_object_array_cluster_elem, classString)) { 

... 

} else if ((*(Record.env))->IsInstanceOf(Record.env, jv_object_array_cluster_elem, classObject)) { 
/* we are about to read the integer array from the arraylist ... */ 

/* get size of integer array */ 
jv_object_array_cluster_elem_size = (*(Record.env))->GetArrayLength(
    Record.env, jv_object_array_cluster_elem); 
/* this case should not happen, the integer array has a minimum entry of 1 element */ 
if (jv_object_array_cluster_elem_size <= 0) 
    continue; 

for (j = 0; j < jv_object_array_cluster_elem_size; j++) { 
    /* get element from integer array */ 
    jv_cluster_data_array_elem = (*(Record.env))->GetObjectArrayElement(
    Record.env, jv_object_array_cluster_elem, j); 
    /* check if null */ 
    if (jv_cluster_data_array_elem == NULL) { 
     break; 

    /* now check type */ 
    /* THIS CALL CRASHES JVM */ 
    if ((*(Record.env))->IsInstanceOf(Record.env, jv_cluster_data_array_elem, 
     classInteger)) { 
     fprintf(stdout, "got array entry of type integer */ 
    } 

    ... 

} /* inner loop integer array */ 

} /* outer loop object array */ 

return 1; 
}

Je ne comprends pas pourquoi il se bloque là-bas, même si je semble ne pas être en mesure d'accéder à ce domaine pour la lecture (avec GetIntField() par exemple). Si j'omets l'appel isInstanceOf (juste en boucle sur le tableau integer) tout va bien, il boucle sur l'arraylist complète, lit mes chaînes et double, boucle sur le tableau entier imbriqué et se termine avec succès. Honnêtement le

Quelqu'un at-il un indice pour moi où regarder ou quoi améliorer? J'espère que l'extrait de code fourni de la fonction de lecteur arraylist est assez complet pour comprendre mon problème. Peut-être que quelqu'un peut me pointer vers la bonne direction sur cette question, je l'espère :-))

J'utilise JRE version: 6.0_22-b04 machine virtuelle Java: Java HotSpot (TM) 64 bits serveur VM (17.1-B03 mode mixte linux-amd64) sur Ubuntu

Merci beaucoup d'avance de m'avoir aidé.

 
Update 2010/12/06: 
================== 
As Peter suggested, I completely reworked the object reader function using the 
Java methods of the object through the native interface. Additionally it 
turned out, that I even do not need that very arraylist I constructed in 
the Java class, I rather used and read the internal class Results Object 
List directly and its object methods to read the results I need. So in short, 
now it is more efficient and I was able to skip that Arraylist construction 
completey and spare one processing step. 

First I thought, using the Java methods of that very class through JNI would 
give me a much higher response time, using Java methods through JNI is surely 
not very fast (compared to using the Java methods in Java directly). Using JNI 
as a bridge from C to Java costs performance and computing time. But anyway, I 
figured out, I am about 200ms faster (using the same data set) than my old 
reader method with the arraylist, so I even gained some performance. 
Ok, to put it in short, using JNI and the Object methods of the Java class 
spared me a lot of headache and the code now is much more readable. 

Conclusion: I would like to encourage everybody that is facing a similar 
problem using the Object methods of the class you work with through JNI. 

Répondre

1

La première chose à noter est que ArrayList! = Un tableau. Les méthodes que vous utilisez pour accéder à l'arraylist ne fonctionnent que pour un tableau.

Je vous suggère d'accéder à ArrayList en appelant les méthodes de la liste comme vous le feriez en Java.

+0

Merci Peter, je comprends ce point ArrayList! = Array. Donc vous suggérez, je devrais retravailler la fonction complète du lecteur et utiliser la méthode Java "get()" enveloppée avec JNI pour lire tous les éléments? Je me demande juste pourquoi tout cela fonctionne jusqu'à maintenant, mais le tableau entier imbriqué ne fonctionne pas. –