JVM Crashs when calling method a 2nd time

Hi Forum,

i have a urgent problem. I call java methods from my c++ code. This works fine if i call the methods only one time. If i try to call the method the second time. I got an execption and the jvm crashes. Here is my c++ code

void GDPNativeOpposite::Init(IN CString pluginPath){

CreateJVM(pluginPath);

m_clazz = m_env->FindClass("com/xxxx/geodatainterface/GeoDataInterface");

ExceptionProver();

m_bitmapMID = m_env->GetMethodID(m_clazz,"getBitmap","(DDDDDDDD)[B");

ExceptionProver();

m_bitmapSizeMID = m_env->GetMethodID(m_clazz,"getBitmapSize","()I");

ExceptionProver();

m_screenSizeMID = m_env->GetMethodID(m_clazz,"changeScreenSize","(II)V");

ExceptionProver();

m_coordInfoPopupMID = m_env->GetMethodID(m_clazz,"getCoordinateInfo","(DD)V");

}

void GDPNativeOpposite::CreateJVM(IN CString pluginPath){

JavaVMInitArgs args;

JavaVMOption cp[3];

HINSTANCE jvmDll= (HINSTANCE)NULL;

jint ( JNICALL *JNI_CreateJavaVM)(JavaVM **pm_vm,void **pm_env,void *args);

// change the current directory to the path of the dll,

// that we can load the dll and all depended dlls

// 1st store the old path

char szOldPath[1024];

GetCurrentDirectory(sizeof(szOldPath), szOldPath);

BOOL fOK = SetCurrentDirectory("C:/Programme/Java/jdk1.5.0_07/jre/bin/client");

//BOOL fOK = SetCurrentDirectory("C:/Programme/Java/jre1.5.0_06/bin/client");

//Load jar files

CString classPath ="";

CreateClassPath(pluginPath, classPath);

cp[0].optionString = classPath.GetBuffer(classPath.GetLength()-1);

classPath.ReleaseBuffer();

cp[1].optionString ="-verbose:jni";

cp[2].optionString ="-Xcheck:jni";

args.version = JNI_VERSION_1_2;//Version

args.nOptions = 2;

args.options = cp;

args.ignoreUnrecognized = TRUE;//Sometimes usefull

jvmDll = LoadLibrary("jvm.dll");//VM library

if( jvmDll == NULL )

{

MessageBox(NULL,"Problem loading VM library","JVM creation error", MB_OK);

}

// Get the .DLL function address of JNI_CreateJavaVM

JNI_CreateJavaVM = (jint (JNICALL *)(JavaVM **,void **, void* ) ) GetProcAddress( jvmDll,"JNI_CreateJavaVM" );

if( !JNI_CreateJavaVM )

{

MessageBox(NULL,"Could not find the JNI_CreateJavaVM function in the specified .DLL","JVM creation error", MB_OK);

}

// Create the VM

jint res = JNI_CreateJavaVM( &m_jvm, (void**) &m_env, &args );

SetCurrentDirectory(szOldPath);

DWORD dwLastErr = GetLastError();

if( res < 0 )

{

MessageBox(NULL,"Could not instantiate the JVM.","JVM creation error", MB_OK);

}

}

void GDPNativeOpposite::CreateClassPath(IN CString pluginPath, OUT CString &csClassPath){

//Some code

}

void GDPNativeOpposite::RecursiveJARSearch(IN CString root, OUT CString &classPath){

//Some code

}

void GDPNativeOpposite::StartJavaOpposite(INlong left, INlong top, INlong right, INlong bottom){

//Create a new instance of the GeoDataInterface class. <init> is constructor call.

jmethodID constrID = m_env->GetMethodID(m_clazz,"<init>","(II)V");

ExceptionProver();

m_instance = m_env->NewObject(m_clazz, constrID, (right-left), (bottom-top));

ExceptionProver();

}

long GDPNativeOpposite::GetBitmap(IN GEODECCOORD ltCoord, IN GEODECCOORD rbCoord, OUT GEOMEMBITMAP* &pBitmap){

JNIEnv* env;

if(m_jvm->AttachCurrentThread((void**)&env, NULL) < 0){

return 0;

}

m_jBitmap = 0L;

ExceptionProver();

m_jBitmap = (jbyteArray)env->CallObjectMethod(m_instance, m_bitmapMID, ltCoord.x, ltCoord.y, rbCoord.x, rbCoord.y, 0, 0, 0, 0);

ExceptionProver();

jsize bitmapSize = m_env->CallIntMethod(m_instance, m_bitmapSizeMID);

pBitmap = (GEOMEMBITMAP*)newbyte[sizeof(GEOMEMBITMAPINFO)+bitmapSize];

m_env->GetByteArrayRegion(m_jBitmap, 14, bitmapSize-14, (jbyte*)pBitmap->gmBitmap);//We don't need the BitmapFILEHeader!!!! So start from offset +14

ExceptionProver();

m_env->ReleaseByteArrayElements(m_jBitmap, m_env->GetByteArrayElements(m_jBitmap, 0), 0);

ExceptionProver();

pBitmap->gmInfo.giLoadBitmapFromDisk = 0;

pBitmap->gmInfo.giApplyPerPixelAlpha = 0;

pBitmap->gmInfo.giApplyReprojection = 0;

pBitmap->gmInfo.giInterpolMethod = imNEARESTNEIGHBOUR;

pBitmap->gmInfo.giMakeTransparentForObjects = 1;

pBitmap->gmInfo.giOriginalProjection = opREAL;

pBitmap->gmInfo.giTransformMethod = tmPRECISE;

return bitmapSize;

}

int GDPNativeOpposite::ExceptionProver(){

//Some code

}

This is the order i call the c++-functions:

Init(path);

StartGDPJavaOpposite(left, top, right, bottom);

GetBitmap(lCoord, rCoord, pBitmap);

GetBitmap(lCoord, rCoord, pBitmap); <-- Crashes here in (jbytearray)env->CallObjectMethod(...)

The global variables are defined in the header:

JNIEnv*m_env;// Declare JNIEnv variable

JavaVM *m_jvm;// Declare virtual machine variable

jobjectm_instance;//Instance of main class (com.xxxx.geodatainterface.GeoDataInterface)

jclassm_clazz;//Pointer to the class (com.xxxx.geodatainterface.GeoDataInterface)

jmethodIDm_bitmapMID;//MethodID of the getBitmap java method

jmethodIDm_screenSizeMID;//MethodID of the proper java method

jmethodIDm_bitmapSizeMID;//MethodID of the proper java method

jmethodIDm_coordInfoPopupMID;//MethodID of the proper java method

jmethodIDm_destroyCoreMID;//MethodID of the proper java method

jbyteArraym_jBitmap;

Message was edited by:

OliverSchwarz

[8562 byte] By [OliverSchwarza] at [2007-10-3 0:54:29]
# 1

Get rid of the global variable JNIEnv* m_env.

Also change m_env references to env in GDPNativeOpposite::GetBitmap method.

Allways rely on global variable JavaVM * m_jvm to retrieve the current JNIEnv* env.

Also you need to create a [url http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/functions.html#NewGlobalRef]global reference[/url] for m_instance so that it won't be discarded by the gc.

You should check for m_jBitmap as well.

Regards

jfbrierea at 2007-7-14 17:49:49 > top of Java-index,Java HotSpot Virtual Machine,Specifications...
# 2

Thanks for the reply.

In the getBitmap method i already use the m_jvm reference to get the JNIEnv! I read the same that you said in a previous thread.

Now i changed all global refs for jmethodID to local calls. Also the jbitmap is changed from global to a local reference. This is the new code:

void GDPNativeOpposite::Init(IN CString pluginPath){

CreateJVM(pluginPath);

JNIEnv* env;

if(m_jvm->AttachCurrentThread((void**)&env, NULL) < 0){

return;

}

jclass clazz = m_env->FindClass("com/xxxx/geodatainterface/GeoDataInterface");

ExceptionProver();

m_clazz = (jclass)env->NewGlobalRef((jobject)clazz);

}

void GDPNativeOpposite::CreateJVM(IN CString pluginPath){

//Nothing changed, works

}

void GDPNativeOpposite::CreateClassPath(IN CString pluginPath, OUT CString &csClassPath){

//working code

}

void GDPNativeOpposite::RecursiveJARSearch(IN CString root, OUT CString &classPath){

//working code

}

void GDPNativeOpposite::StartJavaOpposite(IN long left, IN long top, IN long right, IN long bottom){

JNIEnv* env;

if(m_jvm->AttachCurrentThread((void**)&env, NULL) < 0){

return;

}

//Create a new instance of the GeoDataInterface class. <init> is constructor call.

jmethodID constrID = env->GetMethodID((jclass)m_clazz, "<init>", "(II)V");

ExceptionProver();

jobject instance = env->NewObject((jclass)m_clazz, constrID, (right-left), (bottom-top));

ExceptionProver();

m_instance = env->NewGlobalRef(instance);

}

long GDPNativeOpposite::GetBitmap(IN GEODECCOORD ltCoord, IN GEODECCOORD rbCoord, OUT GEOMEMBITMAP* &pBitmap){

JNIEnv* env;

if(m_jvm->AttachCurrentThread((void**)&env, NULL) < 0){

return 0;

}

ExceptionProver();

jmethodID bitmapMID = env->GetMethodID((jclass)m_clazz, "getBitmap", "(DDDDDDDD)[B");

ExceptionProver();

jbyteArray jBitmap = (jbyteArray)env->CallObjectMethod(m_instance, bitmapMID, ltCoord.x, ltCoord.y, rbCoord.x, rbCoord.y, 0, 0, 0, 0);

ExceptionProver();

jmethodID bitmapSizeMID = env->GetMethodID((jclass)m_clazz, "getBitmapSize", "()I");

ExceptionProver();

jsize bitmapSize = env->CallIntMethod(m_instance, bitmapSizeMID);

pBitmap = (GEOMEMBITMAP*)new byte[sizeof(GEOMEMBITMAPINFO)+bitmapSize];

env->GetByteArrayRegion(jBitmap, 14, bitmapSize-14, (jbyte*)pBitmap->gmBitmap); //We don't need the BitmapFILEHeader!!!! So start from offset +14

ExceptionProver();

env->ReleaseByteArrayElements(jBitmap, env->GetByteArrayElements(jBitmap, 0), 0);

ExceptionProver();

pBitmap->gmInfo.giLoadBitmapFromDisk = 0;

pBitmap->gmInfo.giApplyPerPixelAlpha = 0;

pBitmap->gmInfo.giApplyReprojection = 0;

pBitmap->gmInfo.giInterpolMethod = imNEARESTNEIGHBOUR;

pBitmap->gmInfo.giMakeTransparentForObjects = 1;

pBitmap->gmInfo.giOriginalProjection = opREAL;

pBitmap->gmInfo.giTransformMethod = tmPRECISE;

return bitmapSize;

}

int GDPNativeOpposite::ExceptionProver(){

//working

}

void GDPNativeOpposite::ShutDownVM(){

//working

}

global variables now:

JavaVM* m_jvm;

jclass m_clazz;

jobject m_instance;

But unfortunatly it does not work anyway. It crashes always on the 2nd call of the CallObjectMethod! Its very mysterious, becaus if i step over the CallObjectMethod (in debug mode), i can call the CallIntMethod without any crash! So the m_instance reference must be valid, i think.

Any other suggestions?

OliverSchwarza at 2007-7-14 17:49:49 > top of Java-index,Java HotSpot Virtual Machine,Specifications...
# 3
I solved my problem. I had a nullpointer exception in the thread.
OliverSchwarza at 2007-7-14 17:49:49 > top of Java-index,Java HotSpot Virtual Machine,Specifications...