Я и некоторые товарищи по команде не могли понять, почему следующий фрагмент кода не дает правильного вывода при использовании версий 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 это дает ожидаемый результат. Я не пробовал более ранние версии.
Мы решили назначить награду за этот вопрос! Вот дополнительная информация о том, что мы уже знаем:
. К сожалению для нас, ни один из этих пунктов не приводит к жизнеспособным решениям — «большая проблема», о которой я упоминал, заключалась в том, что мы имеем дело с большим, существующим базу кода с классом C++ с именем «Node», к которому нам нужно получить доступ через JNI. Мы также попробовали несколько вариантов компилятора g++ и javac, а также несколько вариантов JVM, но безрезультатно (хотя, если кто-то наткнется на тот, который действительно дает ожидаемые результаты, это будет приемлемое решение).