JNI用C加载JDK产生JVM虚拟机,并运行JAVA类main函数(MACOS/LINUX/WINDOWS)
Posted 柳鲲鹏
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JNI用C加载JDK产生JVM虚拟机,并运行JAVA类main函数(MACOS/LINUX/WINDOWS)相关的知识,希望对你有一定的参考价值。
技术说明:
- 这里的代码,通过加载libjvm然后找到产生函数。也有的代码直接调用(编译时需要链接)。
- 没有处理参数。
- MAC编译时需要链接 -framework CoreFoundation
Xcode设置编译链接-framework CoreFoundation_柳鲲鹏的博客-CSDN博客
- 根据自己的环境,修改USER_HOME_PATH/JRE_PATH/JAR_FILE_PATH/JAVA_MAIN_CLASS
- 代码如此整齐是六石编程学的要求,阁下应该学习并应用之。
此源码在各系统上都可以运行。WINDOWS上字串处理要特别注意。
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <pthread.h>
#include <jni.h>
#ifdef __APPLE__
#define _DARWIN_BETTER_REALPATH
#include <mach-o/dyld.h>
#include <CoreServices/CoreServices.h>
static void dummyCallback(void * info) ;
#endif
#ifdef _WINDOWS
#define LIB_SUFFIX "dll"
#elif __APPLE__
#define LIB_SUFFIX "dylib"
#else
#define LIB_SUFFIX "so"
#endif
#ifdef _WINDOWS
#define LIB_OPEN LoadLibrary
#define LIB_CLOSE FreeLibrary
#define LIB_METHOD GetProcAddress
#else
#define LIB_OPEN dlopen
#define LIB_CLOSE dlclose
#define LIB_METHOD dlsym
#endif
#define BUFFER_SIZE 256
#define USER_HOME_PATH "/Users/tsit"
#define JRE_PATH USER_HOME_PATH "/tsjdk8-macosx/jre"
#define LIB_JVM_PATH JRE_PATH "/lib/server/libjvm." LIB_SUFFIX
#define JAR_FILE_PATH USER_HOME_PATH "/Develop/tsoffice.jar"
#define JAVA_MAIN_CLASS "com/taishan/Office"
#define JNI_CREATE_JNI "JNI_CreateJavaVM"
/**
从libjvm中找到的函数,产生虚拟机。
*/
typedef int (*CreateJavaVM_t)(JavaVM **ppJvm, void **ppEnv, void *pArgs);
static void* g_pLibHandler = NULL;
static JavaVM* g_pJvm = NULL;
static JNIEnv* g_pJniEnv = NULL;
static jclass g_jMainClass = NULL;
static jmethodID g_jMainMethod = NULL;
/**
从后向前
*/
static void release_for_exit()
g_jMainMethod = NULL;
g_jMainClass = NULL;
if (g_pJniEnv != NULL)
g_pJniEnv->ExceptionDescribe();
g_pJniEnv->ExceptionClear();
g_pJniEnv = NULL;
if (g_pJvm != NULL)
g_pJvm->DestroyJavaVM();
g_pJvm = NULL;
if (g_pLibHandler != NULL)
LIB_CLOSE(g_pLibHandler);
g_pLibHandler = NULL;
static void load_jvm(char* pHomePath, JNIEnv **ppEnv, JavaVM **ppJvm)
char pJvmPath[BUFFER_SIZE] = 0;
strcpy(pJvmPath, LIB_JVM_PATH);
g_pLibHandler = LIB_OPEN(pJvmPath, RTLD_NOW | RTLD_GLOBAL);
if (g_pLibHandler == NULL)
return;
JavaVMOption options[10];
int counter = 0;
options[counter++].optionString = (char*)"-XX:+UseG1GC";
options[counter++].optionString = (char*)"-XX:-UseAdaptiveSizePolicy";
options[counter++].optionString = (char*)"-XX:-OmitStackTraceInFastThrow";
options[counter++].optionString = (char*)"-Xmn512m";
options[counter++].optionString = (char*)"-Xmx2048m";
options[counter++].optionString = (char*)"-Djava.library.path=natives";
memset(pJvmPath, 0, BUFFER_SIZE);
sprintf(pJvmPath, "-Djava.class.path=%s", JAR_FILE_PATH);
options[counter++].optionString = (char*)strdup(pJvmPath);
JavaVMInitArgs vm_args;
memset(&vm_args, 0, sizeof(vm_args));
vm_args.version = JNI_VERSION_1_8;
vm_args.nOptions = counter++;
vm_args.options = options;
vm_args.ignoreUnrecognized = JNI_TRUE;
CreateJavaVM_t pCreateJvmFunction = (CreateJavaVM_t)LIB_METHOD(g_pLibHandler, JNI_CREATE_JNI);
if (pCreateJvmFunction == NULL)
return;
int retCode = pCreateJvmFunction(ppJvm, (void**)ppEnv, &vm_args);
if (retCode != 0 || *ppJvm == NULL || *ppEnv == NULL)
*ppJvm = NULL;
*ppEnv = NULL;
static void run_java_class()
if (g_pJniEnv == NULL)
return;
g_jMainClass = g_pJniEnv->FindClass(JAVA_MAIN_CLASS);
if (g_pJniEnv->ExceptionCheck() == JNI_TRUE || g_jMainClass == NULL )
return;
g_jMainMethod = g_pJniEnv->GetStaticMethodID(g_jMainClass, "main", "([Ljava/lang/String;)V");
if (g_pJniEnv->ExceptionCheck() == JNI_TRUE || g_jMainMethod == NULL)
return;
g_pJniEnv->CallStaticVoidMethod(g_jMainClass, g_jMainMethod, NULL);
void* thread_function(void* pData)
char pHomePath[512] = 0;
load_jvm(pHomePath, &g_pJniEnv, &g_pJvm);
run_java_class();
return NULL;
int main(const int argc, const char** argv)
#ifdef __APPLE__
//如此奇怪的代码是吾同事搞定的。不这样就不对。
pthread_t tid;
pthread_create(&tid, NULL, thread_function, NULL);
CFRunLoopSourceContext sourceContext =
.version = 0, .info = NULL, .retain = NULL,
.release = NULL, .copyDescription = NULL, .equal = NULL,
.hash = NULL, .schedule = NULL, .cancel = NULL,
.perform = &dummyCallback;
CFRunLoopRef loopRef = CFRunLoopGetCurrent();
CFRunLoopSourceRef sourceRef = CFRunLoopSourceCreate(NULL, 0, &sourceContext);
CFRunLoopAddSource(loopRef, sourceRef, kCFRunLoopCommonModes);
CFRunLoopRun();
CFRelease(sourceRef);
#else
thread_function(NULL);
#endif
release_for_exit();
return 0;
以上是关于JNI用C加载JDK产生JVM虚拟机,并运行JAVA类main函数(MACOS/LINUX/WINDOWS)的主要内容,如果未能解决你的问题,请参考以下文章
无法加载 JNI 共享库“C:\Program Files\Java\jdk\1.7.0_45\bin\...\jre\bin\server\jvm.dll”