JNI将String转换为char*,由实例方法返回



在我的程序中,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相对应的字段envobj,以及同时初始化的getIdJava实例方法的methodIDjvm.getId。调试宏只是用flush调用printf,它可以帮助我调试程序。

这是调用get_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

正如您所看到的,对JavagetId的调用(看起来)是成功的,但核心转储是由GetStringUTFChars触发的。

怎么了?

您不能缓存JVM的env。请参阅保持对JNIEnv环境的全局引用,尤其是以下答案:

JNI接口指针(JNIEnv)仅在当前线如果另一个线程需要访问Java虚拟机,它必须首先调用AttachCurrentThread()将自身附加到VM并获得JNI接口指针。一旦连接到VM,本机线程工作方式与在本机中运行的普通Java线程一样方法本机线程保持连接到VM,直到它调用DetachCurrentThread()以分离自身。

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

至于Java对象、类和方法id,如果要缓存它们,则需要获得对它们的全局引用。查看What is';JNI Global reference';缓存JNI对象和线程安全(在Android中)

最新更新