JVM сбой при чтении ArrayList из Java-класса с JNI - PullRequest
1 голос
/ 04 декабря 2010

У меня проблемы с чтением arraylist из класса Java с jni. В Java-классе arraylist определяется следующим образом:

public static List XTN_STC_search_result = new ArrayList();

Массив затем заполняется строкой, значением счёта как double и массивом целых чисел. Итак, структура выглядит так: [ [label str 1, score value 1, [int 1, int 2, int n]], [label str 2, score value 2, [int 1, int 2], ... ]

На стороне JNI C я делаю следующее, чтобы прочитать этот список.

После прочтения статического поля и получения объекта я зацикливаюсь на массиве, чтобы прочитать все значения. Все идет хорошо, я могу прочитать каждую запись массива, строку метки, двойное значение и получить доступ к массиву целых чисел с помощью вложенного цикла. В рамках вложенного цикла извлекайте запись целочисленного массива с помощью getObjectArrayElement, и, похоже, она получает это значение. После этого я проверяю его на NULL, и это не NULL. Чтобы быть педантичным, я дважды проверяю, является ли запись массива (целочисленного массива) экземпляром Integer с помощью isInstanceOf. Именно этот вызов приводит к сбою моей программы с SIGSEGV, и JVM выдает ошибку.

Ниже вы видите фрагмент кода проблемной области ...

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

Я не понимаю, почему там происходит сбой, хотя мне кажется, что я не могу получить доступ к этому полю для чтения (например, с помощью GetIntField ()). Если я пропущу вызов isInstanceOf (просто зацикливаясь на целочисленном массиве), все пойдет нормально, он зацикливается на полном массиве, читает мои строки и удваивается, зацикливается на вложенном целочисленном массиве и успешно завершается. Честно говоря,

Кто-нибудь подскажет мне, где искать или что улучшить? Я надеюсь, что предоставленный фрагмент кода функции чтения архива достаточно полон, чтобы понять мою проблему. Может быть, кто-то может указать мне правильное направление в этом вопросе, надеюсь: -))

я использую Версия JRE: 6.0_22-b04 Java VM: Java HotSpot (TM) 64-разрядная серверная виртуальная машина (17.1-b03 смешанный режим linux-amd64) на Ubuntu

Большое спасибо заранее за помощь в этом.

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.

1 Ответ

1 голос
/ 04 декабря 2010

Первое, что нужно отметить, это то, что ArrayList! = Массив. Методы, которые вы используете для доступа к массиву, работают только для массива.

Я предлагаю вам получить доступ к ArrayList, вызывая методы List точно так же, как в Java.

...