因为工作需要,研究了一下Java如何调用Dll的方法,最开始设计的接口是直接返回自定义的对象,对象的申请和构造都在jin的实现方法中(即在DLL中申请构造java的自定义对象),结果运行一段时间后,就会出现崩溃情况:
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x6d898683, pid=1260, tid=6152
#
# Java VM: Java HotSpot(TM) Client VM (11.0-b15 mixed mode windows-x86)
# Problematic frame:
# V [jvm.dll+0x98683]
#
# If you would like to submit a bug report, please visit:
# http://java.sun.com/webapps/bugreport/crash.jsp
#
--------------- T H R E A D ---------------
Current thread (0x0238d400): VMThread [stack: 0x020e0000,0x02130000] [id=6152]
siginfo: ExceptionCode=0xc0000005, reading address 0x00000001
Registers:
EAX=0x00000001, EBX=0x08d2d1e8, ECX=0x0212fa10, EDX=0x6d9e0a08
ESP=0x0212f808, EBP=0x0212f868, ESI=0x08d2d1a0, EDI=0x0212fa10
EIP=0x6d898683, EFLAGS=0x00010283
Top of Stack: (sp=0x0212f808)
0x0212f808: 083f6c00 08d2d1a0 6d8b6763 08d2d1a0
0x0212f818: 08d2d190 08d2d1f0 08d2d200 0212f868
0x0212f828: 083f6a70 083f6c04 6d97e2b1 08d2d190
0x0212f838: 0212f868 08d2d000 02307f68 08d2d000
0x0212f848: 08d2d200 6d97e13b 08d2d000 00000080
0x0212f858: 00000061 08d2d200 0212f868 0238d770
0x0212f868: 6d9f802c 02307f68 083e0000 0212fa10
0x0212f878: 6d97e065 08d2d000 00000080 08d2cff8
Instructions: (pc=0x6d898683)
0x6d898673: 24 08 8b 06 85 c0 57 8b f9 74 55 3b 47 1c 73 50
0x6d898683: 8b 08 83 e1 03 80 f9 03 75 1f 8a 0d dd 15 a1 6d
Stack: [0x020e0000,0x02130000], sp=0x0212f808, free space=318k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V [jvm.dll+0x98683]
.......
后查看了网上的相关资料后发现,这种方式非常不合理,不利于内存空间的管理,极易造成内存释放引发程序崩溃。本着在那里申请在那里释放的原因,处理相关参数,是比较合理的方式。后把程序改成,在jin接口中传入在java中定义的对象,然后在dll中对对象的字段进行赋值操作,这样对象的定义、内存的申请、以及最后的释放,都统一在java中完成,很好地解决的崩溃问题。具体的示例如下:
//java中的类及接口--------------------------------------------------------------------------------------------------------------------------------
package fhcom;
public class Student {
public int nNumber = 0;
public int nAge = 0;
public String strName = "";
public String strHome = "";
}
public class ZxdcLib {
/*获取一个学生信息*/
public static native int getStudent(Student student);
/*获取一组学生信息*/
public static native int getArrStudent(Student[] arrStudent);
static{
System.loadLibrary("JinZxdcLib");
}
}
//通过调用javac javah 生成的头文件------------------------------------------------------------------------------
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class fhcom_ZxdcLib */
#ifndef _Included_fhcom_ZxdcLib
#define _Included_fhcom_ZxdcLib
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: fhcom_ZxdcLib
* Method: getStudent
* Signature: (Lfhcom/Student;)I
*/
JNIEXPORT jint JNICALL Java_fhcom_ZxdcLib_getStudent
(JNIEnv *, jclass, jobject);
/*
* Class: fhcom_ZxdcLib
* Method: getArrStudent
* Signature: ([Lfhcom/Student;I)I
*/
JNIEXPORT jint JNICALL Java_fhcom_ZxdcLib_getArrStudent
(JNIEnv *, jclass, jobjectArray);
#ifdef __cplusplus
}
#endif
#endif
//把头文件加入到Dll中,实现其方法----------------------------------------------------
// JinZxdcLib.cpp : Defines the entry point for the DLL application.
//
#include <Windows.h>
#include "stdafx.h"
#include "fhcom_ZxdcLib.h"
#ifdef _MANAGED
#pragma managed(push, off)
#endif
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}
#ifdef _MANAGED
#pragma managed(pop)
#endif
//将jstring类型转换成windows类型
char* jstringToWindows( JNIEnv *env, jstring jstr )
{
int length = (env)->GetStringLength(jstr );
const jchar* jcstr = (env)->GetStringChars(jstr, 0 );
char* rtn = (char*)malloc( length*2+1 );
int size = 0;
size = WideCharToMultiByte( CP_ACP, 0, (LPCWSTR)jcstr, length, rtn,(length*2+1), NULL, NULL );
if( size <= 0 )
{
return NULL;
}
(env)->ReleaseStringChars(jstr, jcstr );
rtn[size] = 0;
return rtn;
}
//将windows类型转换成jstring类型
jstring WindowsTojstring( JNIEnv* env, const char* str )
{
jstring rtn = 0;
int slen = strlen(str);
unsigned short * buffer = 0;
if( slen == 0 )
{
rtn = (env)->NewStringUTF(str );
}
else
{
int length = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, NULL, 0 );
buffer = (unsigned short *)malloc( length*2 + 1 );
if( MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str, slen, (LPWSTR)buffer, length ) >0 )
{
rtn = (env)->NewString( (jchar*)buffer, length );
}
}
if( buffer )
{
free( buffer );
}
return rtn;
}
/*通过参数传递对象,赋值后返回*/
JNIEXPORT jint JNICALL Java_fhcom_ZxdcLib_getStudent
(JNIEnv *pEnv, jclass cls, jobject obj)
{
jclass myClass = (pEnv)->FindClass("fhcom/Student");
if (myClass == NULL)
{
return 1;
}
jfieldID idNumber = (pEnv)->GetFieldID(myClass, "nNumber", "I");
jfieldID idAge = (pEnv)->GetFieldID(myClass, "nAge", "I");
jfieldID idName = (pEnv)->GetFieldID(myClass, "strName", "Ljava/lang/String;");
jfieldID idHome = (pEnv)->GetFieldID(myClass, "strHome", "Ljava/lang/String;");
(pEnv)->SetIntField(obj, idNumber, 2001001);
(pEnv)->SetIntField(obj, idAge, 22);
(pEnv)->SetObjectField(obj, idName, WindowsTojstring(pEnv, "wang feng"));
(pEnv)->SetObjectField(obj, idHome, WindowsTojstring(pEnv, "Henan"));
return 0;
}
/*通过参数传递对象数组(必须初始化),赋值后返回*/
JNIEXPORT jint JNICALL Java_fhcom_ZxdcLib_getArrStudent
(JNIEnv *pEnv, jclass cls, jobjectArray objArr)
{
jclass myClass = (pEnv)->FindClass("fhcom/Student");
if (myClass == NULL)
{
return 1;
}
jint nArrLen = (pEnv)->GetArrayLength(objArr);
for (int i=0; i<nArrLen; i++)
{
jobject objTemp = (pEnv)->GetObjectArrayElement(objArr, i);
jclass clsTemp = (pEnv)->GetObjectClass(objTemp);
jfieldID idNumber = (pEnv)->GetFieldID(clsTemp, "nNumber", "I");
jfieldID idAge = (pEnv)->GetFieldID(clsTemp, "nAge", "I");
jfieldID idName = (pEnv)->GetFieldID(clsTemp, "strName", "Ljava/lang/String;");
jfieldID idHome = (pEnv)->GetFieldID(clsTemp, "strHome", "Ljava/lang/String;");
(pEnv)->SetIntField(objTemp, idNumber, 2001001+i);
(pEnv)->SetIntField(objTemp, idAge, 22+i);
(pEnv)->SetObjectField(objTemp, idName, WindowsTojstring(pEnv, "wang feng"));
(pEnv)->SetObjectField(objTemp, idHome, WindowsTojstring(pEnv, "Henan"));
}
return 0;
}