java - C + JNI 无法执行一个非常简单的程序

标签 java c java-native-interface jnienv

我将从我的代码开始:

#include <jni.h>

int main(int argc, char const *argv[]) {
  JavaVMInitArgs args;
  JNIEnv *env;
  JavaVM *vm;

  args.version = JNI_VERSION_1_8;
  args.ignoreUnrecognized = JNI_FALSE;

  JNI_CreateJavaVM(&vm, (void **)&env, &args);

  jclass System;
  jclass PrintStream;

  jobject out;
  jfieldID outID;
  jstring someText;
  jmethodID println;

  someText = (*env)->NewStringUTF(env, "Hello World");

  System = (*env)->FindClass(env, "java/lang/System");
  PrintStream = (*env)->FindClass(env, "java/io/PrintStream");

  outID = (*env)->GetStaticFieldID(env, System, "out", "Ljava/io/PrintStream;");
  out = (*env)->GetStaticObjectField(env, System, outID);
  println = (*env)->GetMethodID(env, PrintStream, "println", "(Ljava/lang/String;)V");

  (*env)->CallVoidMethod(env, out, println, someText);

  return 0;
}

我希望它打印“Hello World”,但它没有,相反,我得到了段错误(核心转储)烦人的错误。我无法弄清楚这段代码有什么问题,我尝试注释掉 someText = (*env)->NewStringUTF(env, "Hello World"); 之后的所有内容,但程序没有崩溃时,我还尝试仅注释 someText = (*env)->NewStringUTF(env, "Hello World"); 并且我也工作了。我什至将 println 签名更改为 "boolean" 并将 0 传递给它,程序按照我的预期打印了“false”,所以我猜这是 的问题NewStringUTF 方法。

openjdk 版本“1.8.0_131” OpenJDK 运行时环境(内部版本 1.8.0_131-b11) OpenJDK 64 位服务器虚拟机(版本 25.131-b11,混合模式)

(gdb) bt
#0  0x00007ffff713b2ff in ?? () from /usr/lib/jvm/java-8-openjdk/jre/lib/amd64/server/libjvm.so
#1  0x00007ffff78955c4 in ?? () from /usr/lib/jvm/java-8-openjdk/jre/lib/amd64/server/libjvm.so
#2  0x00007ffff7507e71 in JNI_CreateJavaVM () from /usr/lib/jvm/java-8-openjdk/jre/lib/amd64/server/libjvm.so
#3  0x0000000000400558 in main (argc=1, argv=0x7fffffffe678) at main.c:11


(gdb) info f
Stack level 0, frame at 0x7fffffffe310:
 rip = 0x7ffff713b2ff; saved rip = 0x7ffff78955c4
 called by frame at 0x7fffffffe490
 Arglist at 0x7fffffffe2c8, args: 
 Locals at 0x7fffffffe2c8, Previous frame's sp is 0x7fffffffe310
 Saved registers:
  rbx at 0x7fffffffe2d8, rbp at 0x7fffffffe300, r12 at 0x7fffffffe2e0, r13 at 0x7fffffffe2e8, r14 at 0x7fffffffe2f0,
  r15 at 0x7fffffffe2f8, rip at 0x7fffffffe308

注释掉NewStringUTF

(gdb) bt
#0  0x00007fffe61082b4 in ?? ()
#1  0x0000000000000246 in ?? ()
#2  0x00007fffe6108160 in ?? ()
#3  0x00007fffffffe0f0 in ?? ()
#4  0x00007fffffffe090 in ?? ()
#5  0x00007ffff78f6748 in ?? () from /usr/lib/jvm/java-8-openjdk/jre/lib/amd64/server/libjvm.so
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

(gdb) info f
Stack level 0, frame at 0x7fffffffde80:
 rip = 0x7fffe61082b4; saved rip = 0x246
 called by frame at 0x7fffffffde88
 Arglist at 0x7fffffffde70, args: 
 Locals at 0x7fffffffde70, Previous frame's sp is 0x7fffffffde80
 Saved registers:
  rip at 0x7fffffffde78

经过一些观察,看起来函数 JNI_CreateJavaVM 在添加 NewStringUTF 后崩溃,但在删除后它“正常工作”。这有多奇怪?

这是我正在使用的 JDK 和 JRE:https://www.archlinux.org/packages/extra/x86_64/jdk8-openjdk/

我正在使用此命令进行编译:

gcc \
-I /usr/lib/jvm/java-8-openjdk/include/ \
-I /usr/lib/jvm/java-8-openjdk/include/linux/ \
-L /usr/lib/jvm/java-8-openjdk/jre/lib/amd64/server/ \
-l jvm \
main.c

并使用

运行文件
export LD_LIBRARY_PATH=/usr/lib/jvm/java-8-openjdk/jre/lib/amd64/server/
./a.out

第二天

不同的代码,相同的问题:

#include <jni.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char const *argv[]) {
  JavaVMInitArgs args;
  JavaVM *jvm;
  JNIEnv *env;

  args.version = JNI_VERSION_1_8;
  args.ignoreUnrecognized = JNI_FALSE;

  printf("%s\n", "Creating VM");

  JNI_CreateJavaVM(&jvm, (void **)&env, &args);

  printf("%s\n", "VM Was Created");

  jclass String = (*env)->FindClass(env, "java/lang/String");

  if (String == NULL) {
    printf("%s\n", "String was NULL");
    exit(1);
  }

  jmethodID method = (*env)->GetMethodID(env, String, "codePointAt", "(I)I");

  if (method == NULL) {
    printf("%s\n", "method was NULL");
    exit(1);
  }

  printf("%s\n", "I am finishing here");

  (*jvm)->DestroyJavaVM(jvm);
  return 0;
}

编译并运行:

$ gcc \
> -I /usr/lib/jvm/java-8-openjdk/include/ \
> -I /usr/lib/jvm/java-8-openjdk/include/linux/ \
> -L /usr/lib/jvm/java-8-openjdk/jre/lib/amd64/server/ \
> -l jvm \
> main.c && ./a.out
Creating VM
Segmentation fault (core dumped)

但是如果我评论代码部分:

#include <jni.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char const *argv[]) {
  JavaVMInitArgs args;
  JavaVM *jvm;
  JNIEnv *env;

  args.version = JNI_VERSION_1_8;
  args.ignoreUnrecognized = JNI_FALSE;

  printf("%s\n", "Creating VM");

  JNI_CreateJavaVM(&jvm, (void **)&env, &args);

  printf("%s\n", "VM Was Created");

  jclass String = (*env)->FindClass(env, "java/lang/String");

  if (String == NULL) {
    printf("%s\n", "String was NULL");
    exit(1);
  }

  /*jmethodID method = (*env)->GetMethodID(env, String, "codePointAt", "(I)I");

  if (method == NULL) {
    printf("%s\n", "method was NULL");
    exit(1);
  }*/

  printf("%s\n", "I am finishing here");

  (*jvm)->DestroyJavaVM(jvm);
  return 0;
}

编译并运行:

$ gcc \
> -I /usr/lib/jvm/java-8-openjdk/include/ \
> -I /usr/lib/jvm/java-8-openjdk/include/linux/ \
> -L /usr/lib/jvm/java-8-openjdk/jre/lib/amd64/server/ \
> -l jvm \
> main.c && ./a.out
Creating VM
VM Was Created
I am finishing here

最佳答案

所以,对我来说,它按预期工作:

> gdb ./main
...
(gdb) run
Starting program: ..../issue/main
[New Thread 0x1403 of process 2600]
[New Thread 0x1503 of process 2600]
warning: unhandled dyld version (15)
Hello World
[Inferior 1 (process 2600) exited normally]
(gdb)

但是,我的环境略有不同。 macOS 和我使用 Oracle 的 JDK。

也许你可以尝试安装调试信息并检查 JDK 内部到底发生了什么?

关于java - C + JNI 无法执行一个非常简单的程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44991293/

相关文章:

java - Android jni中如何释放字符串?

java - 给定排序数组,如果数组 A 包含元素 A[i] 且 A[i] = i (递归和分而治之),则返回索引 i

c - 如何在没有 float 的情况下提高准确性 C

c - sleep 函数是让所有线程都 sleep 还是只让调用它的线程 sleep ?

C++ 和微软 SAPI 5 : How to list all available voices and select a voice

java - 从 JNI 创建 Java 枚举

java - 从 Java 使用 ScriptEngine 调用自定义脚本函数

java - 形成和执行 if 语句的问题

java - 从 Apache Commons-Exec 捕获大量输出

c - 编写一个 c 函数,生成一个随机数,或一对随机数,或给定特定范围的三组随机数