다른 사람이 이미 문제없이
- 당신은 정적 C++ 변수에
jmethodID
를 저장할 수를 썼던 것처럼
- 당신은
jobject
또는 정적 C++ 변수에 jclass
env->NewGloablRef()
를 호출하여 전역 개체로 변환 후 로컬에 저장할 수 있습니다
그냥 여기에 추가 정보를 추가하고 싶습니다 : 정적 C++ 변수 wi에 jclass를 저장하는 주요 이유 매번 env->FindClass()
번으로 전화하는 것이 성능 문제라고 생각하십니까?
그러나 은 Windows에서 QueryPerformanceCounter()
API를 사용하는 성능 카운터를 사용하여을 FindClass()
으로 측정했습니다. 3,6 GHz의 CPU와 컴퓨터
jcass p_Container = env->FindClass("java/awt/Container");
의 실행 0.01 MS 0.02 MS 사이에 필요에
: 그리고 그 결과는 놀라웠다. 그것은 엄청나게 빠릅니다. Java 소스 코드를 살펴본 후 클래스가 저장되어있는 Dictionary를 사용합니다. 이것은 매우 효율적으로 구현되는 것 같습니다.
는 좀 더 클래스를 테스트하고 여기 결과입니다
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
위의 값은 자바 이벤트 디스패처 스레드에서입니다. 나에 의해 CreateThread()
에 의해 생성 된 네이티브 Windows 스레드에서 동일한 코드를 실행하면 도 더 빨리 실행됩니다.. 왜?
FindClass()
을 매우 자주 호출하지 않으면 전역 참조를 만든 다음 정적 변수에 저장하는 대신 JNI 함수를 호출 할 때 필요시 호출 할 수 있습니다.
또 다른 중요한 주제 스레드 안전입니다. Java에서 각 스레드는 자신의 독립적 인 JNIEnv
구조를가집니다.
jobject
또는 jclass
은 모든 Java 스레드에서 유효합니다.
- 로컬 개체는 호출 스레드의
JNIEnv
에있는 하나의 함수 호출에서만 유효하며 JNI 코드가 Java로 반환 될 때 가비지 수집됩니다.당신이 세계로, 나중에 사용하려면, 당신은 env->RegisterNatives()
와 C++ 함수를 등록하고 자바 코드는 다음 모든 개체를 저장해야합니다 JNI 함수로 호출하는 경우 :
지금 당신이 사용하는 스레드에 따라 달라집니다 그렇지 않으면 가비지 수집됩니다.
하지만 당신은 (윈도우에서) CraeteThread()
API를 사용하여 자신의 스레드를 생성하고 AttachCurrentThreadAsDaemon()
를 호출하여 JNIEnv
구조를 얻을 경우 다음 완전히 다른 규칙이 적용됩니다 : 그것은 자바, 쓰레기로 제어를 반환하지 않습니다 자신의 스레드이기 때문에 컬렉터는 쓰레드에서 생성 한 객체를 결코 지울 수 없으며 로컬 객체를 문제없이 정적 C++ 변수에 저장할 수도 있습니다! (하지만 다른 스레드에서는 액세스 할 수 없습니다.)이 경우에는 env->DeleteLocalRef()
으로 모든 로컬 인스턴스를 수동으로 정리해야합니다. 그렇지 않으면 메모리 누수가 발생합니다.
모든 로컬 객체를 소멸자에 DeleteLocalRef()
을 호출하는 래퍼 클래스에로드하는 것이 좋습니다. 이것은 메모리 누출을 피하는 총알이없는 방법입니다.
JNI 코드를 개발하는 것은 매우 복잡 할 수 있으며 사용자가 이해하지 못하는 충돌이 발생할 수 있습니다.
java -Xcheck:jni -jar MyApplication.jar
은 다음 JNI 코드에서 일어난 어떤 문제가 표시됩니다 충돌의 원인은 DOS 창을 열고 다음 명령을 사용하여 Java 응용 프로그램을 시작 찾을 수 있습니다.
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x6e8655d5, pid=4692, tid=4428
#
etc...
JNI가 자동으로'에 의해 반환되는 로컬 참조를 정리 : 자바 당신이 JAR 파일이 같은 폴더에 생성 로그 파일의 스택 트레이스를 찾을 수
및 예를 들면 : FindClass' 자바 측으로 돌아갈 때. –
따라서 '최대' 이 링크 (http://java.sun.com/docs/books/jni/html/other.html)의 – bmargulies
은 NewWeakGlobalRef를 사용합니다. 나는 약한 참조로 시도 할 것이다. – YuppieNetworking