我有一个使用JNI嵌入JVM并支持各种Java版本的C应用程序。该应用程序运行在linux、OSX和windows上。
目前,它允许通过环境变量提供JVM args,但我希望使它更智能。
不幸的是,我需要根据Java版本不同地设置一些VM参数。
如果我有一个使用JNIEnv*的GetVersion,我就可以得到这个版本了--但是当我有了一个JNIEnv*时,我已经建立了一个JVM,但为时已晚。(您不能关闭并重新启动一个新JVM。)
看起来,JNI_GetDefaultJavaVMInitArgs可以做到这一点--但是,尽管它编译的很好,但我无法从它得到一个合理的答案。例如,使用Java 9:
JavaVMInitArgs vmArgs;
vmArgs.version = JNI_VERSION_1_2;
if (JNI_GetDefaultJavaVMInitArgs(&vmArgs)!=JNI_OK) {
fprintf(stderr, "JNI_GetDefaultJavaVMInitArgs failed!\n");
};
fprintf(stderr, "Query with version = %x\n", JNI_VERSION_1_2);
fprintf(stderr, "JAVA version = %x\n", vmArgs.version);版画
Query with version = 10002
JAVA version = 10002也就是说,它还没有更新版本。
有没有办法(以跨平台的方式)获取这些信息?我在使用JNI_GetDefaultJavaVMInitArgs时做错了什么吗?
发布于 2022-06-14 11:05:03
为什么不先做最简单的事情,然后在一个单独的进程中启动一个JVM来计算JVM版本:
int fds[2];
pipe(fds);
if (fork() == 0) { // child
close(fds[0]);
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_2;
vm_args.options = nullptr;
vm_args.nOptions = 0;
vm_args.ignoreUnrecognized = true;
JNIEnv *env = nullptr;
jint res = JNI_CreateJavaVM(&vm, (void **)&env, &vm_args);
jclass cls_Runtime = env->FindClass("java/lang/Runtime");
jmethodID mid_version = env->GetStaticMethodID("version", "()Ljava/lang/Runtime$Version;");
jobject obj_Version = env->CallStaticObjectMethod(cls_Runtime, mid_getVersion);
jclass cls_Version = env->GetObjectClass(obj_Version);
jmethodID mid_toString = env->getMethodID(cls_Version, "toString", "()Ljava/lang/String;");
jstring str_Version = (jstring) env->CallObjectMethod(obj_version, mid_toString);
const char *version = env->GetStringUTFChars(str_Version, null);
write(fds[1], version, env->GetStringUTFLength(str_Version));
exit(0);
} else if (fork() > 0) { // parent
close(fds[1]);
char version[100];
int size = read(fds[0], version, 100);
close(fds[0]);
version[size] = '\0';
// continue initialization
} else { // error }当然,与调用toString不同,您只需抓取feature()即可。
发布于 2022-06-23 02:55:13
您必须区分JNI和JVM。每个JVM版本都支持一组JNI,这取决于其版本(最新列表请参见https://docs.oracle.com/en/java/javase/18/docs/specs/jni/functions.html#version-information )。当您请求激活JVM时,您必须设置您的应用程序编写的JNI的最小版本;C链接是增量式的,例如,GetModule可以从版本9中获得。如果您使用CreateJavaVM的最高版本调用JNI而不是JVM支持的版本,则API返回JNI_EVERSION。
如果应用程序的参数依赖于JVM版本,则JNI版本是无用的:最新的JNI版本是10,从JRE 10到JRE 18是相同的。
为了能够调用JNI,您必须加载JVM主库。当加载JVM库时,您将决定使用哪个版本的JVM,从而决定JNI版本。一个系统可以安装多个JVM,一个是默认的,另一个是可以使用jvm.dll、libjvm.so等路径访问的。一般来说,JVM的版本是在路径中编写的,它取决于规范、构建、供应商、平台等许多方面。这是apt的输出:
sudo apt install openjdk-11-jre-headless # version 11.0.10+9-0ubuntu1~20.04, or
sudo apt install default-jre # version 2:1.11-72
sudo apt install openjdk-8-jre-headless # version 8u282-b08-0ubuntu1~20.04
sudo apt install openjdk-13-jre-headless # version 13.0.4+8-1~20.04
sudo apt install openjdk-14-jre-headless # version 14.0.2+12-1~20.04您可以解析JVM库的路径,试图标识JRE规范(8、11、13、.)然后,您可以使用应用程序为该版本所需的参数调用CreateJavaVM。
https://stackoverflow.com/questions/72614118
复制相似问题