我有一个JNI DLL,它在类对象上使用GetFieldID()时会崩溃,并传递给函数。该库在Linux上运行良好,具有32位和64位JVM,在Windows下使用32位时只会崩溃 - 64位就可以了。
使用MinGW-w64 GCC 4.6.3在ubuntu 13.10 x86_64上交叉编译原始DLL,但我也使用MinGW-w64 GCC 4.6.3在Windows下本地编译它,我仍然遇到了同样的崩溃。使用带有MinGW-w64 4.8.2的ubuntu 14.04仍会产生相同的错误。
似乎存在一些内存损坏,因为当我使用未经优化的DLL时,崩溃不会发生在GetFieldID()上的第一次调用,但是在稍后的版本上(原始DLL的代码多于下面的简化示例)或者甚至在函数在JVM垃圾收集中的某处完成之后。
我使用的JVM是Java 7u60,但我也尝试使用8u5并得到了相同的结果。我在64位和32位系统上使用32位JVM对它进行了测试,因为我看到一篇文章说,32位JVM在64位Windows操作系统上可能不可靠(听起来有点)对我来说是虚假的,但只是为了确定。)
还有其他JNI DLL,它们根本不使用GetFieldID(),而且它们在32位工作正常。
来自hs_err_pid.log的崩溃数据
Current thread (0x00d5e000): JavaThread "main" [_thread_in_native, id=1104, stack(0x00dd0000,0x00e20000)]
siginfo: ExceptionCode=0xc0000005, ExceptionInformation=0x00000008 0x3462c9e8
Registers:
EAX=0x00000000, EBX=0x00e1f1fc, ECX=0x97254d7c, EDX=0x00d5eac4
ESP=0x00e1f1dc, EBP=0x00e1f1ec, ESI=0x3462c6e8, EDI=0x00d5e000
EIP=0x3462c9e8, EFLAGS=0x00010246
Top of Stack: (sp=0x00e1f1dc)
0x00e1f1dc: 00000000 3462c6e8 00000000 00e1f1fc
0x00e1f1ec: 00e1f224 025f334f 246970c0 025f88c9
0x00e1f1fc: 24695668 2460b700 00e1f204 34628d1b
0x00e1f20c: 00e1f22c 34628ee8 00000000 34628d40
0x00e1f21c: 00e1f1fc 00e1f22c 00e1f25c 025f3207
0x00e1f22c: 24693760 24693760 00000001 24693758
0x00e1f23c: 00e1f234 34628c56 00e1f264 34628ee8
0x00e1f24c: 00000000 34628c88 00e1f22c 00e1f268
Instructions: (pc=0x3462c9e8)
0x3462c9c8: 78 bc 62 34 50 bb 62 34 c0 bd 62 34 30 bd 62 34
0x3462c9d8: 00 00 00 00 00 00 00 00 0c 00 00 00 02 00 00 00
0x3462c9e8: 01 00 00 00 60 f9 5f 39 02 00 00 00 a0 b9 62 34
0x3462c9f8: 0a 00 b8 00 10 d6 00 39 00 00 00 00 01 00 40 80
Register to memory mapping:
EAX=0x00000000 is an unknown value
EBX=0x00e1f1fc is pointing into the stack for thread: 0x00d5e000
ECX=0x97254d7c is an unknown value
EDX=0x00d5eac4 is an unknown value
ESP=0x00e1f1dc is pointing into the stack for thread: 0x00d5e000
EBP=0x00e1f1ec is pointing into the stack for thread: 0x00d5e000
ESI=0x3462c6e8 is an oop
{method}
- klass: {other class}
EDI=0x00d5e000 is a thread
Stack: [0x00dd0000,0x00e20000], sp=0x00e1f1dc, free space=316k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C 0x3462c9e8
j jnitest.JNIClass.<init>()V+27
j jnitest.JNIClass.getInstance()Ljnitest/JNIClass;+22
j jnitest.Program.main([Ljava/lang/String;)V+0
v ~StubRoutines::call_stub
V [jvm.dll+0x140e6a]
V [jvm.dll+0x20529e]
V [jvm.dll+0x140eed]
V [jvm.dll+0x14d2ee]
V [jvm.dll+0x14d515]
V [jvm.dll+0xf1f99]
C [java.dll+0x7d82]
j sun.reflect.NativeMethodAccessorImpl.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+87
j sun.reflect.DelegatingMethodAccessorImpl.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+6
j java.lang.reflect.Method.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+57
j com.intellij.rt.execution.application.AppMain.main([Ljava/lang/String;)V+163
v ~StubRoutines::call_stub
V [jvm.dll+0x140e6a]
V [jvm.dll+0x20529e]
V [jvm.dll+0x140eed]
V [jvm.dll+0xca5c5]
V [jvm.dll+0xd5267]
C [java.exe+0x2063]
C [java.exe+0xa5d1]
C [java.exe+0xa65b]
C [kernel32.dll+0x1338a]
C [ntdll.dll+0x39f72]
C [ntdll.dll+0x39f45]
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j jnitest.JNIWrapper.createUuid(Ljnitest/JNIWrapper$sender_id_t;)I+25
j jnitest.JNIClass.<init>()V+27
j jnitest.JNIClass.getInstance()Ljnitest/JNIClass;+22
j jnitest.Program.main([Ljava/lang/String;)V+0
v ~StubRoutines::call_stub
j sun.reflect.NativeMethodAccessorImpl.invoke0(Ljava/lang/reflect/Method;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+0
j sun.reflect.NativeMethodAccessorImpl.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+87
j sun.reflect.DelegatingMethodAccessorImpl.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+6
j java.lang.reflect.Method.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+57
j com.intellij.rt.execution.application.AppMain.main([Ljava/lang/String;)V+163
v ~StubRoutines::call_stub
Java类:
package jnitest;
public class JNIClass {
static final Object _mutex = new Object();
static JNIClass _instance = null;
public static JNIClass getInstance()
{
if (_instance == null)
{
synchronized (_mutex)
{
if (_instance == null)
_instance = new JNIClass();
}
}
return _instance;
}
JNIWrapper.sender_id_t sid = null;
JNIClass() {
//create uuid
sid = new JNIWrapper.sender_id_t();
System.out.print(JNIWrapper.createUuid(sid));
}
}
JNI包装类:
package jnitest;
public final class JNIWrapper {
static {
System.loadLibrary("JNIWrapper");
}
public static class sender_id_t
{
public long phy_idx;
}
public static native int createUuid(JNIWrapper.sender_id_t id);
}
申请表:
package jnitest;
public class Program
{
public static void main(String[] args)
{
JNIClass.getInstance();
System.exit(0);
}
}
自动生成的JNI DLL标头:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class jnitest_JNIWrapper */
#ifndef _Included_jnitest_JNIWrapper
#define _Included_jnitest_JNIWrapper
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: jnitest_JNIWrapper
* Method: createUuid
* Signature: (Ljnitest/JNIWrapper/sender_id_t;)I
*/
JNIEXPORT jint JNICALL Java_jnitest_JNIWrapper_createUuid
(JNIEnv *, jclass, jobject);
#ifdef __cplusplus
}
#endif
#endif
JNI DLL实现(更新为能够使用C或C ++接口):
#include "jnitest_JNIWrapper.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
#define JNIFUNC(e,f) e->f()
#define JNIFUNCV(e,f,...) e->f(__VA_ARGS__)
#else
#define JNIFUNC(e,f) (*e)->f(e)
#define JNIFUNCV(e,f,...) (*e)->f(e,__VA_ARGS__)
#endif
JNIEXPORT jint JNICALL Java_jnitest_JNIWrapper_createUuid(JNIEnv *env, jclass clazz, jobject sid)
{
(void)clazz;
jclass cls = JNIFUNCV(env,GetObjectClass, sid);
jfieldID phyID = JNIFUNCV(env,GetFieldID, cls, "phy_idx", "J");
(void)phyID;
if (JNIFUNC(env,ExceptionCheck))
return 100;
return 0;
}
#ifdef __cplusplus
}
#endif
更新
编译命令:
i686-w64-mingw32-gcc -std=c99 -O3 -s -Wall -Wextra -Werror -o ../bin/JNIWrapper.dll -shared -Wl,--subsystem,windows dllmain.c JNIWrapper.c -I /usr/lib/jvm/java-7-openjdk-amd64/include
答案 0 :(得分:0)
您正在尝试获取内部类的字段ID,但您的cls变量是外部类JNIWrapper。您可能需要运行类似(* env) - &gt; FindClass(env,&#34; jnitest / JNIWrapper $ sender_id_t&#34;)以获取正确的cl来调用get field id。 javap -c
工具可以告诉您&#34; jnitest / JNIWrapper $ sender_id_t&#34;应该。