JVM не работает должным образом с JNI C++ код, содержащий класс с именем «Node»

Я и некоторые товарищи по команде не могли понять, почему следующий фрагмент кода не дает правильного вывода при использовании версий JVM с 1.6u23 по 1.6u31 (последняя на момент публикации). Этот фрагмент кода представляет собой упрощение более крупной проблемы:

ОБНОВЛЕНИЕ: Пример немного изменен, чтобы сосредоточить внимание на проблеме, связанной с тем, что "virtual_function()" не вызывается.

ОБНОВЛЕНИЕ: пример еще больше упрощен на основе последних комментариев.

NodeTester.cpp:

#include <iostream>
#include <jni.h>

class Node {
  public:
    Node () :m_counter(0) {}
    virtual ~Node () {}

    virtual void virtual_function () {
      m_counter += 10;
    }

    void non_virtual_function () {
      m_counter += 1;
    }

    int get_counter () {
      return m_counter;
    }

  private:
    int m_counter;

};

extern "C" {
  JNIEXPORT void JNICALL Java_NodeTester_testNode (JNIEnv *jni_env_rptr, 
                                                   jclass java_class) {
    Node *node_rptr = new Node();
    node_rptr->non_virtual_function();
    node_rptr->virtual_function();

    std::cout << node_rptr->get_counter() << std::endl;

    delete node_rptr;
  }
}

NodeTester.java:

public class NodeTester {
  public static native void testNode ();

  static {
    System.loadLibrary("nodetester");
  }

  public static final void main (String[] args) {
    NodeTester.testNode();
  }
}

ожидаемый вывод:

11

фактический вывод с JVM от 1.6u23 до 1.6u31:

1

Похоже, что JVM неправильно создает объект «Узел» внутри ИНИ; хотя возможно, что в этом коде есть что-то неправильное в использовании JNI. Когда к классу «Узел» добавляется больше функциональности (например, больше атрибутов, дополнительные виртуальные и невиртуальные операции), мы можем вызвать ошибку сегментации, а не просто неправильный вывод. Мы компилируем код cpp в 64-разрядную библиотеку общих объектов RedHat linux с помощью g++ и запускаем код Java с помощью 64-разрядной виртуальной машины сервера. Обратите внимание, что на JVM от 1.6u20 до 1.6u22 это дает ожидаемый результат. Я не пробовал более ранние версии.

Мы решили назначить награду за этот вопрос! Вот дополнительная информация о том, что мы уже знаем:

  • JVM 1.6u22 (и более ранние версии) дают ожидаемые результаты
  • Переименование «узла» или помещение его в пространство имен дает ожидаемые результаты
  • Выделение объекта «узел» в стеке вместо кучи в функции JNI дает ожидаемые результаты
  • Нет проблем с невиртуальными компонентами класса «Узел»

. К сожалению для нас, ни один из этих пунктов не приводит к жизнеспособным решениям — «большая проблема», о которой я упоминал, заключалась в том, что мы имеем дело с большим, существующим базу кода с классом C++ с именем «Node», к которому нам нужно получить доступ через JNI. Мы также попробовали несколько вариантов компилятора g++ и javac, а также несколько вариантов JVM, но безрезультатно (хотя, если кто-то наткнется на тот, который действительно дает ожидаемые результаты, это будет приемлемое решение).

24
задан Tom 20 March 2012 в 15:15
поделиться