Java JNI将字符串转换为由实例方法返回的char*

Java JNI将字符串转换为由实例方法返回的char*,java,c,java-native-interface,Java,C,Java Native Interface,在我的程序中,C是从Java调用的,C函数可以在Java上下文之外调用,但有时需要一些Java资源。我应该解释一下程序是什么。。。所以C库是一个可以加载C插件的插件系统,插件有时需要访问Java资源,例如检索字符串id 因此,当加载插件系统时,JNI会调用一个init函数,这样就可以存储JNIEnv*和jobject以供插件进一步访问 在java类中,我提供了访问这些资源的实例方法,例如,我有方法 private String getId() { return "Bryan"; } C插件

在我的程序中,C是从Java调用的,C函数可以在Java上下文之外调用,但有时需要一些Java资源。我应该解释一下程序是什么。。。所以C库是一个可以加载C插件的插件系统,插件有时需要访问Java资源,例如检索字符串id

因此,当加载插件系统时,JNI会调用一个init函数,这样就可以存储
JNIEnv*
jobject
以供插件进一步访问

在java类中,我提供了访问这些资源的实例方法,例如,我有方法

private String getId() {
  return "Bryan";
}
C插件系统有一个功能

char *get_id(char *id) {
  jobject jobj = (*jvm.env)->CallObjectMethod(jvm.env, jvm.this, jvm.getId);
  jstring jid = jobj;
  if (jid == NULL) 
    debug("get_id", RED "jid NULL");
   else 
     debug("get_id", RED "jid not null"); */
  debug("get_id", RED "in get_id, method called");
  const char *cid = (*jvm.env)->GetStringUTFChars(jvm.env, jid, NULL);
  debug("get_id", RED "converted to c string: %s", cid);
  strcpy(id, cid);
  debug("get_id", RED "string copied");
  (*jvm.env)->ReleaseStringUTFChars(jvm.env, jid, cid);
  debug("get_id", RED "string released");
  return id;
}
其中,jvm是一个结构,包含与初始化时存储的
JNIEnv*
jobject
相对应的
env
obj
字段,以及
jvm.getId
字段,后者是同时被序列化的
getId
Java实例方法的
methodID
。 调试宏只是调用
printf
,使用
flush
,帮助我调试程序

这是调用
get\u id
后的输出:

DEBUG IN plugin_system.c LINE 339:
In get_id
in get_id, calling method...
DEBUG IN plugin_system.c LINE 343:
In get_id
jid NULL
DEBUG IN plugin_system.c LINE 346:
In get_id
in get_id, method called
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007fb6bcb6cd70, pid=25254, tid=0x00007fb6974be700
#
# JRE version: OpenJDK Runtime Environment (8.0_92-b14) (build 1.8.0_92-b14)
# Java VM: OpenJDK 64-Bit Server VM (25.92-b14 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# V  [libjvm.so+0x675d70]
#
# Core dump written. Default location: /home/kowa/code/reseaux/projet/ringo/java/bin/core or core.25254
#
# An error report file with more information is saved as:
# /home/kowa/code/reseaux/projet/ringo/java/bin/hs_err_pid25254.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
[4]    25254 abort (core dumped)  java Jring Nick 9999 8888 1
正如您所看到的,对Java
getId
的调用(看起来)是成功的,但是核心转储是由
GetStringUTFChars
触发的


怎么了?

您不能缓存JVM的
env
。尤其见:

JNI接口指针(JNIEnv)仅在当前 线如果另一个线程需要访问Java VM,它必须 首先调用AttachCurrentThread()将自身连接到VM并获取 JNI接口指针。一旦连接到VM,本机线程 工作原理与在本机中运行的普通Java线程类似 方法。在调用之前,本机线程将一直连接到VM DetachCurrentThread()来分离自身

。另一个答案中的链接已过时


至于Java对象、类和方法id,如果要缓存它们,则需要将它们转换为Java对象、类和方法id。请参见和

什么是您的
jvm
对象?建筑?一节课?你怎么填写?通常,不能缓存JVM
env
值等值。也不能缓存对象或方法ID,除非创建一个,该字段在加载库之后,在对本机init函数进行java调用之后填充。首先,您对C字符串使用哪种字符集和编码,系统默认还是特定的?谢谢,我不知道。我已经修改了代码,所以现在这个结构只包含一个指向JVM的指针和一个指向对象的全局引用。每次从“纯C上下文”调用JNI时,我都会在调用之前调用
AttachCurrentThread
。我仍然得到一个错误:
JNIEnv*env;jint rs=(*jvm.jvm)->AttachCurrentThread(jvm.jvm,&env,NULL);断言(rs==JNI_OK);rs=(*jvm.jvm)->DetachCurrentThread(jvm.jvm);断言(rs==JNI_OK),断言是由调用
DetachCurrentThread
触发的……您所说的“纯C上下文”是什么意思?根据:“连接到VM的本机线程必须在退出之前调用DetachCurrentThread()以分离自身。如果调用堆栈上有Java方法,则线程无法分离自身。”您可能不需要调用
DetachCurrentThread()
。在启动插件加载的初始JNI函数中打印出
env
的值,然后在调用
DetachCurrentThread()
的位置再次打印。它可能是相同的,因为它是相同的线程。