通过 JNI NewObject 创建实例时 jvm.dll 中的异常 0xC0000005
Exception 0xC0000005 in jvm.dll when creating an instance via JNI NewObject
我正在编写 a plug-in for an existing application. Implementation language is C. However, the actual functionality is implemented in Java. For this reason, I am using Java Native Interface (JNI) 从 C 中创建一个 JVM 实例。我可以找到合适的 Java class 并创建一个实例。代码如下所示:
login(uintptr_t connection, const char* username, …) {
…
jmethodID constructor = (*env)->GetMethodID(env, ps->class, "<init>", "(JLjava/lang/String;)V");
jstring jusername = (*env)->NewStringUTF(env, username);
jobject instance = (*env)->NewObject(env, ps->class, constructor, connection, jusername);
一切正常。
在 Linux。
在Windows,简直一团糟。一旦我尝试创建 Java class 的实例,它就会抛出
EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0813751f, pid=8, tid=0x00000009
。更多详细信息已写入日志文件,但堆栈跟踪除了指向 jvm.dll 中的某处外没有任何帮助。使用调试器单步执行并不是很有见地。请注意,这与 .
不同
几天后,我想通了。
我正在调用的构造函数需要一个参数。类型是 long
(Java) 又名 J
(JNI 类型签名)又名 jlong
(相应的 C 类型)。 C uintptr_t
与 jlong
.
兼容
在 Linux 上,我的 uintptr_t
长 8 个字节,因为我在 amd64 环境中使用 64 位应用程序。对于 Windows,应用程序是在 32 位中构建的。结果 uintptr_t
只有 4 个字节长,但 JVM 仍然需要 8 个字节 jlong
。然而,NewObject
是一个可变参数函数,不会自动提升,类型安全也得不到保证。
login(uintptr_t connection, const char* username, …) {
…
jmethodID constructor = (*env)->GetMethodID(env, ps->class, "<init>", "(JLjava/lang/String;)V");
jstring jusername = (*env)->NewStringUTF(env, username);
jlong jconnection = connection;
jobject instance = (*env)->NewObject(env, ps->class, constructor, jconnection, jusername);
简单地转换为正确的类型就是解决方案。我希望 CallVoidMethod
或任何 Call*Method
mentioned in the documentation 也存在这个陷阱。
我正在编写 a plug-in for an existing application. Implementation language is C. However, the actual functionality is implemented in Java. For this reason, I am using Java Native Interface (JNI) 从 C 中创建一个 JVM 实例。我可以找到合适的 Java class 并创建一个实例。代码如下所示:
login(uintptr_t connection, const char* username, …) {
…
jmethodID constructor = (*env)->GetMethodID(env, ps->class, "<init>", "(JLjava/lang/String;)V");
jstring jusername = (*env)->NewStringUTF(env, username);
jobject instance = (*env)->NewObject(env, ps->class, constructor, connection, jusername);
一切正常。
在 Linux。
在Windows,简直一团糟。一旦我尝试创建 Java class 的实例,它就会抛出
EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0813751f, pid=8, tid=0x00000009
。更多详细信息已写入日志文件,但堆栈跟踪除了指向 jvm.dll 中的某处外没有任何帮助。使用调试器单步执行并不是很有见地。请注意,这与
几天后,我想通了。
我正在调用的构造函数需要一个参数。类型是 long
(Java) 又名 J
(JNI 类型签名)又名 jlong
(相应的 C 类型)。 C uintptr_t
与 jlong
.
在 Linux 上,我的 uintptr_t
长 8 个字节,因为我在 amd64 环境中使用 64 位应用程序。对于 Windows,应用程序是在 32 位中构建的。结果 uintptr_t
只有 4 个字节长,但 JVM 仍然需要 8 个字节 jlong
。然而,NewObject
是一个可变参数函数,不会自动提升,类型安全也得不到保证。
login(uintptr_t connection, const char* username, …) {
…
jmethodID constructor = (*env)->GetMethodID(env, ps->class, "<init>", "(JLjava/lang/String;)V");
jstring jusername = (*env)->NewStringUTF(env, username);
jlong jconnection = connection;
jobject instance = (*env)->NewObject(env, ps->class, constructor, jconnection, jusername);
简单地转换为正确的类型就是解决方案。我希望 CallVoidMethod
或任何 Call*Method
mentioned in the documentation 也存在这个陷阱。