GetEnv() の処理は, HotSpot 内に静的に確保されている JNIEnv 構造体のアドレスをリターンするだけ (<= 正確に言うと JVMTIEnv をリターンすることもあるが... (See: here for details)).
ただし, HotSpot 内に静的に確保されている JNIEnv には 2種類ある (通常時用とデバッグ時用). どちらが使われるかはコマンドラインオプションの -Xcheck:jni の有無で決まる.
jni_NativeInterface
通常時 (= -Xcheck:jni オプションが指定されていない場合) に使われる JNIEnv.
HotSpot 内では jni_functions_nocheck() というアクセサでアクセスされる (が, 直接参照されている箇所もあったりする...).
checked_jni_NativeInterface
デバッグ時 (-Xcheck:jni オプションが指定された場合) に使われる JNIEnv. この中に納められている JNI 関数は, 通常の JNI 関数の処理に加えて様々な実行時チェックを行う.
HotSpot 内では jni_functions_check() というアクセサでアクセスされる.
また, 実際に native method を呼び出したり JNI 関数を使用する際は, 上記の大域変数 (jni_NativeInterface, checked_jni_NativeInterface) が直接使用されるわけではない. 代わりに, 各 JavaThread が jni_environment というフィールドを持っており, そこに実際に使用する JNIEnv を格納している. native method の呼び出しや JNI 関数では, カレントスレッドの JavaThread::jnienvironment() から JNIEnv を取得して処理が行われる.
((cite: hotspot/src/share/vm/runtime/thread.hpp))
// Returns the jni environment for this thread
JNIEnv* jni_environment() { return &_jni_environment; }
なお, -Xcheck:jni オプションの有無は, HotSpot 内部では CheckJNICalls という変数で管理されている.
上述の通り, 各 JavaThread が自分の使う JNIEnv を保持しているが, スレッド毎に使う JNIEnv が変わるわけでもないので, どの JavaThread も指している先は同じになっている.
-Xcheck:jni オプションが指定された場合には, unchecked_jni_NativeInterface という static 変数に通常時用の JNIEnv が格納されている.
(実際の処理時には, チェック処理が行われた後, この変数経由で通常時の JNIEnv の関数が呼ばれて JNI 処理が実行される)
((cite: hotspot/src/share/vm/prims/jniCheck.cpp))
static struct JNINativeInterface_ * unchecked_jni_NativeInterface;
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.