Jak inni już napisali
- Można przechowywać
jmethodID
w zmiennej statycznej C++ bez problemów
- można przechowywać lokalnej
jobject
lub jclass
w zmiennej statycznej C++ po konwersji ich do globalnych obiektów wywołując env->NewGloablRef()
Po prostu chcę dodać dodatkowe informacje tutaj: Głównym powodem przechowywania jclass w statycznej zmiennej C++ wi Będziesz uważał za problem z wydajnością wywoływanie za każdym razem env->FindClass()
.
Ale I zmierzył prędkość z FindClass()
z licznikiem wydajności z interfejsem API QueryPerformanceCounter()
w systemie Windows. I wynik był zaskakujący:
Na moim komputerze z procesorem 3,6 GHz, a jest wykonanie
jcass p_Container = env->FindClass("java/awt/Container");
trwa między 0,01 i 0,02 ms ms. To jest niesamowicie szybkie. Zajrzałem do kodu źródłowego Javy i wykorzystałem słownik, w którym przechowywane są klasy. Wydaje się, że wdraża się to bardzo skutecznie.
Testowałem trochę więcej klas i oto wynik:
Elapsed 0.002061 ms for java/net/URL
Elapsed 0.044390 ms for java/lang/Boolean
Elapsed 0.019235 ms for java/lang/Character
Elapsed 0.018372 ms for java/lang/Number
Elapsed 0.017931 ms for java/lang/Byte
Elapsed 0.017589 ms for java/lang/Short
Elapsed 0.017371 ms for java/lang/Integer
Elapsed 0.015637 ms for java/lang/Double
Elapsed 0.018173 ms for java/lang/String
Elapsed 0.015895 ms for java/math/BigDecimal
Elapsed 0.016204 ms for java/awt/Rectangle
Elapsed 0.016272 ms for java/awt/Point
Elapsed 0.001817 ms for java/lang/Object
Elapsed 0.016057 ms for java/lang/Class
Elapsed 0.016829 ms for java/net/URLClassLoader
Elapsed 0.017807 ms for java/lang/reflect/Field
Elapsed 0.016658 ms for java/util/Locale
Elapsed 0.015720 ms for java/lang/System
Elapsed 0.014669 ms for javax/swing/JTable
Elapsed 0.017276 ms for javax/swing/JComboBox
Elapsed 0.014777 ms for javax/swing/JList
Elapsed 0.015597 ms for java/awt/Component
Elapsed 0.015223 ms for javax/swing/JComponent
Elapsed 0.017385 ms for java/lang/Throwable
Elapsed 0.015089 ms for java/lang/StackTraceElement
Powyższe wartości są od dyspozytora wydarzenie wątku Java. Jeśli wykonam ten sam kod w natywnym wątku systemu Windows, który został utworzony przez mnie CreateThread()
, działa on nawet 10 razy szybciej. Czemu?
Tak więc, jeśli nie wywołuje się często FindClass()
, nie ma absolutnie żadnego problemu z wywoływaniem go na żądanie, gdy wywoływana jest funkcja JNI zamiast tworzenia globalnego odniesienia i zapisywania go w zmiennej statycznej.
Innym ważnym tematem jest bezpieczeństwo wątek. W Javie każdy wątek ma własną niezależną strukturę JNIEnv
.
- Globalne
jobject
lub jclass
są ważne w każdym wątku Java.
- Obiekty lokalne są ważne tylko w jednym wywołaniu funkcji w
JNIEnv
wątku wywołującego i są śmieciami zbierane, gdy kod JNI wraca do Java.
Teraz to zależy od gwintów, że używasz: Jeśli zarejestrujesz swój C funkcję ++ z env->RegisterNatives()
i kod Java dzwoni do swoich funkcji JNI następnie trzeba przechowywać wszystkie obiekty, które chcesz użyć później, jako globalny obiekty w przeciwnym razie będą zbierać śmieci.
Ale jeśli stworzysz swój własny wątek z CraeteThread()
API (w systemie Windows) i uzyskanie struktury JNIEnv
wywołując AttachCurrentThreadAsDaemon()
następnie całkowicie zastosuje inne zasady: Jak to jest swój własny wątek, że nigdy nie zwraca sterowanie do Java, śmieci kolekcjoner nigdy nie oczyści obiektów, które utworzyłeś w swoim wątku, a możesz nawet przechowywać lokalne obiekty w statycznych zmiennych C++ bez problemów! (Ale nie można uzyskać do nich dostępu z innych wątków) W takim przypadku bardzo ważne jest, aby ręcznie usunąć WSZYSTKIE lokalne wystąpienia za pomocą env->DeleteLocalRef()
, w przeciwnym razie wystąpi przeciek pamięci.
Zdecydowanie zaleca się załadowanie WSZYSTKICH obiektów lokalnych do klasy opakowania, która wywołuje DeleteLocalRef()
w swoim destruktorze. Jest to skuteczny sposób na uniknięcie wycieków pamięci.
Opracowanie kodu JNI może być bardzo uciążliwe i może dojść do awarii, których nie rozumiesz. Aby znaleźć przyczynę awarii otworzyć okno DOS i uruchomić aplikację Java za pomocą następującego polecenia:
java -Xcheck:jni -jar MyApplication.jar
wtedy zobaczysz jakie problemy się stało w kodzie JNI. Na przykład:
FATAL ERROR in native method: Bad global or local ref passed to JNI
i znajdą Państwo StackTrace w pliku dziennika, który Java tworzy w tym samym folderze gdzie masz plik JAR:
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x6e8655d5, pid=4692, tid=4428
#
etc...
JNI automatycznie czyści lokalnych odniesień zwróconych przez ' FindClass' po powrocie do strony Java. –
w ten sposób "co najwyżej". – bmargulies
w tym łączu (http://java.sun.com/docs/books/jni/html/other.html) używają NewWeakGlobalRef. Spróbuję z słabym odniesieniem. – YuppieNetworking