在 Windows 上使用 Cygwin 編譯的 JNI 動態庫(依賴 cygwin1.dll),直接用標準 java 或 javaw.exe 啟動 JVM 時,System.loadLibrary() 會導致進程死鎖。根因:Cygwin DLL 需要 Cygwin 進程上下文才能正確初始化,而標準啟動器不是 Cygwin 進程。
編寫一個 Cygwin 原生 C 程序 作為 JVM 啟動器,利用 JNI Invocation API 創建 JVM。因為啟動器本身在 Cygwin 環境下編譯鏈接,擁有完整的 Cygwin 運行時上下文,後續加載依賴 cygwin1.dll 的 JNI 庫即可正常工作。
typedef struct JavaVMInitArgs {
jint version; // 必須 JNI_VERSION_1_2 或以上
jint nOptions;
JavaVMOption *options; // JVM 選項陣列
jboolean ignoreUnrecognized;
} JavaVMInitArgs;
typedef struct JavaVMOption {
char *optionString; // 如 "-Djava.class.path=..."
void *extraInfo;
} JavaVMOption;
LoadLibrary("jvm.dll") 載入 JVM 動態庫GetProcAddress 獲取 JNI_CreateJavaVM 函數指針JavaVMInitArgs:類路徑、庫路徑、JIT 開關等JNI_CreateJavaVM(&jvm, &env, &vm_args) 創建 JVM 實例JNIEnv 尋找主類、獲取 main 方法 ID、調用 CallStaticVoidMethod 啟動 Java 應用JavaVMInitArgs vm_args;
JavaVMOption options[4];
options[0].optionString = "-Djava.compiler=NONE";
options[1].optionString = "-Djava.class.path=c:\\myclasses";
options[2].optionString = "-Djava.library.path=c:\\mylibs";
options[3].optionString = "-verbose:jni";
vm_args.version = JNI_VERSION_1_2;
vm_args.options = options;
vm_args.nOptions = 4;
vm_args.ignoreUnrecognized = JNI_TRUE;
typedef jint (JNICALL *CreateJavaVM_t)(JavaVM**, void**, void*);
HINSTANCE hinst = LoadLibrary("jvm.dll");
CreateJavaVM_t pfnCreateJavaVM = (CreateJavaVM_t)GetProcAddress(hinst, "JNI_CreateJavaVM");
JavaVM *jvm; JNIEnv *env;
jint res = pfnCreateJavaVM(&jvm, (void**)&env, &vm_args);
if (res < 0) { /* error handling */ }
// 啟動主類
jclass cls = (*env)->FindClass(env, mainClassName);
jmethodID mid = (*env)->GetStaticMethodID(env, cls, "main", "([Ljava/lang/String;)V");
(*env)->CallStaticVoidMethod(env, cls, mid, appArgs);
# Cygwin Shell 中編譯
g++ cvm.cpp -o javaw.exe
bin/javaw.exe,替換為編譯產出的 javaw.exeexport PATH=/cygdrive/c/tools/eclipse3.2/:$PATH; eclipseexport PATH=/cygdrive/c/tutorial/jni_libs/:$PATHj2re1.4.2_06標準啟動器 = 非 Cygwin 進程 → 加載 Cygwin JNI 庫死鎖
自製啟動器 = Cygwin 進程 → 擁有 Cygwin 上下文 → 正常加載 JNI 庫
此方案在 Eclipse + Cygwin + JNI 混合開發場景下經過實戰驗證,屬於「治標又治本」的工程級變通方案。