JNI и C ++ объектные экземпляры - PullRequest
2 голосов
/ 28 апреля 2009

Я только начал новую работу. Здесь мы новички в использовании JNI (для соединения C ++ / Java). Я новичок в JNI, так что, пожалуйста, прости меня за noobness:)

В нашем (win32) Java-приложении мы загружаем C ++ DLL. На стороне Java у нас есть несколько экземпляров SomeJClass, каждому из которых требуется доступ к соответствующему экземпляру SomeCClass на стороне DLL. DLL предоставляет точки входа, такие как GlobalDoSomethingInC (). Здесь я должен вызвать метод экземпляра Doer :: DoSomethingInC (). Поэтому мне нужен плавный способ сопоставления соответствующих указателей this. Я также должен сделать то же самое отображение, когда поток DLL обнаруживает что-то интересное, о чем он должен уведомить соответствующий экземпляр Java.

Я могу придумать несколько решений, но мне они не очень нравятся. У меня вопрос, есть ли лучший способ, чем этот?

1 Java вызывает C: GetNewInstance (). Это возвращает int, который фактически является указателем на новый экземпляр C. Java хранит его в m_myCInstance. Затем Java вызывает GlobalDoSomethingInC () и 1а

// DLL global
void GlobalDoSomethingInC()
{
    // retrive this pointer
    //calling back to Java:  
    jobj tmpJ = NewGlobalRef( env, obj );
    Doer* myDoer = <reinterpret_cast>( Doer )tmpJ->GetMyCInstance();
    myDoer->DoSomething();
    DeleteGlobalRef( env, tmpJ );
    // Arrrrgh
}

1b или:

    // for **every call** that Java adds a parameter, 
    //which is the stored int:m_myCInstance, and
    Doer* myDoer = <reinterpret_cast>( Doer )instanceParam->DoSomethingInC();
    // Can we do better that this?

2 Для звонков из C в Java все выглядит, может быть, лучше

In the constructor C calls back into Java and stores
the Java instance reference 
    in a member variable. m_myJInstance.
    In all subsequent calls m_myJInstance can be used to call back Java.
    In the destructor we need to call DeleteGlobalRef( env, m_myJInstance );

Не так уж и плохо, я полагаю. Но действительно безопасно хранить ссылку на задание. Я имею в виду: что происходит, когда ГК перемещает объект?

3 Наше настоящее решение работает. Но это относится скорее к http://www.codinghorror.com/blog/:)

Thanx

Ответы [ 2 ]

2 голосов
/ 28 апреля 2009

Обычно это будет зависеть от вашей среды. Я использовал только KNI, который еще более примитивен, чем JNI. Я думаю, что немало уродства неизбежно, поскольку вы смешиваете отслеживание памяти в двух системах, только в одной из которых есть GC.

В общем, я нашел, что лучше всего обернуть все вызовы кода C в функции, которые позаботились о грязном приведении, которое, я думаю, неизбежно. (Кстати, я буду использовать C для обозначения не Java-кода здесь)

На стороне C перемещение объектов Java, безусловно, является потенциальной проблемой. Это будет зависеть от вашей платформы, но я ожидаю, что, пока вы находитесь в lib, вы не можете ожидать появления Java GC, поэтому ваши объекты стабильны. ВЫ ДОЛЖНЫ БЫТЬ УВЕРЕНЫ В ЭТОМ. С другой стороны, если это не так, вы в значительной степени облажались. Предполагая, что это так, вы хотите сделать то же самое, изолировав разыменование / приведение к функции, которая работает с JNI, чтобы вы могли счастливо работать с обычными объектами C во всех вызываемых функциях.

Что может быть действительно уродливым, так это то, что вы можете позволить объектам выходить из области видимости с обеих сторон, поскольку потенциально любая сторона может удерживать ссылку на ваш объект. Здесь мы использовали финализаторы на стороне Java, а также деструкторы на стороне C. Это было не красиво, но я думаю, что это несколько неизбежно.

Итак, короткий ответ, это будет несколько уродливо, изолировать уродство вокруг интерфейса между двумя языками, так что для большей части работы на любом языке вам не придется беспокоиться о таких вещах.

Также стоит иметь базовый класс для объектов, существующих в этом интерфейсе, так как здесь вы также можете выделить некоторые уродства.

0 голосов
/ 01 мая 2013

jobject - это непрозрачная ручка для объекта. Может отличаться в реализации (см. Android 2.x против 4.x), но просто поверьте, что это непрозрачный объект.

Текущее решение, вероятно, правильное. Если вы должны хранить jobject в собственном коде, вы должны преобразовать его в глобальную ссылку. Если вы вызываете NewGlobalRef, то счетчик ссылок объекта увеличивается и не будет утилизироваться, пока вы не вызовете DeleteGlobalRef (и GC не заметил, что это иначе недоступно)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...