Сам себе и некоторым товарищам по команде не удалось понять, почему следующий фрагмент кода не даст правильного вывода при использовании версий JVM версии 1.6u23 до 1.6u31 (последние из этой публикации). Этот фрагмент кода представляет собой упрощение более крупной проблемы:
UPDATE: слегка изменил пример, чтобы сосредоточить внимание на проблеме, которая, по-видимому, не вызвана вызовом virtual_function().
UPDATE: упростить пример еще больше, основываясь на комментариях к дате.
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 неправильно создает объект "Node" в JNI; хотя возможно, что в этом коде есть что-то неправильное в отношении использования JNI. Когда класс "Node" добавляет к нему больше функциональности (например, больше атрибутов, дополнительных виртуальных и не виртуальных операций), мы можем вызвать ошибку сегментации, а не просто некорректный вывод. Мы компилируем код cpp в 64-битную библиотеку общих ресурсов RedHat с использованием g++ и запускаем код java с 64-разрядной VM сервера. Обратите внимание, что на JVM 1.6u20 до 1.6u22 это дает ожидаемый результат. Я не пробовал более ранние версии.
Мы решили поставить щедрость на этот вопрос! Здесь больше информации о том, что мы уже знаем:
- JVMs 1.6u22 (и предшествующие) дают ожидаемые результаты
- Переименование "Node" или помещение его в пространство имен дает ожидаемые результаты
- Выделение объекта "Node" в стеке вместо кучи в функции JNI дает ожидаемые результаты
- Нет проблем с не виртуальными компонентами класса "Node"
К сожалению, для нас ни один из этих элементов не приводит к жизнеспособным решениям - "большая проблема", о которой я говорил, заключалась в том, что мы имеем дело с большой существующей базой кода с классом С++ с именем "Node" , который мы необходимо получить доступ через JNI. Мы также попробовали несколько параметров компилятора g++ и javac, а также несколько параметров JVM, но безрезультатно (хотя, если кто-то спотыкается на то, что действительно дает ожидаемые результаты, это было бы приемлемым решением).