Я и некоторые товарищи по команде не смогли понять, почему следующий фрагмент кода не даст правильного вывода при использовании версий 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 неправильно создает объект "Node" в JNI;хотя возможно, что в этом коде есть что-то неправильное в использовании JNI.Когда класс «Узел» получает больше функциональности (например, больше атрибутов, дополнительные виртуальные и не виртуальные операции), мы можем вызвать ошибку сегментации, а не просто неправильный вывод.Мы компилируем код cpp в 64-разрядную библиотеку RedHat Linux с использованием g ++ и запускаем код Java с 64-разрядной виртуальной машиной сервера.Обратите внимание, что на JVM 1.6u20 - 1.6u22 это дает ожидаемый результат.Я не пробовал более ранние версии.
Мы решили назначить награду за этот вопрос!Вот более подробная информация о том, что мы уже знаем:
- JVM 1.6u22 (и более ранние) дают ожидаемые результаты
- Переименование "узла" или помещение его в пространство имен дает ожидаемые результаты
- Размещение объекта «Узел» в стеке вместо кучи в функции JNI дает ожидаемые результаты
- Нет проблем с не виртуальными компонентами класса «Узел»
К сожалению, для нас ни один из этих элементов не привел к жизнеспособным решениям - «большая проблема», на которую я ссылался, заключалась в том, что мы имеем дело с большой существующей базой кода с классом C ++ под названием «Node», который нам нужендоступ через JNI.Мы также попробовали несколько опций компилятора g ++ и javac и несколько опций JVM, но безрезультатно (хотя, если кто-то наткнется на тот, который действительно даст ожидаемые результаты, это будет приемлемым решением).