JNI freeing local references
843829Jul 6 2004 — edited Jul 8 2004We're using JNI to receive data from a native callback function. The native side creates local references, but does not use the DeleteLocalRef function. This works fine with the SUN JRE.
However, the IBM JRE gets a stack overflow exception.
According to IBM, we should delete the local references, but this requires a total rewrite of our program.
Unfortunately, the JNI documentation is not very clear on this topic. In our understanding, the local references are being released automatically once they are out of scope.
Is it really necessary to delete the local references or is there a bug in the IBM JRE ?
Sample program :
==============
// JNITest.java
interface INativeNotification
{
public void nativeCallBack();
}
class JNITest implements INativeNotification
{
private long counter;
public native void nativeInitialize(INativeNotification callbackNotification);
static {
System.loadLibrary("JNITest");
}
public void nativeCallBack() {
System.out.println("JNITest CallBack " + counter++);
}
public void run() {
nativeInitialize(this);
counter = 0;
while(true)
{
try {
Thread.sleep(1000);
} catch(Exception e) {
}
}
}
public static void main(String[] args) {
JNITest jnitest = new JNITest();
jnitest.run();
}
}
// JNITest.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include "JNITest.h"
static DWORD dwThreadId;
static HANDLE hThread;
static HANDLE volatile hInitCompleteEvent;
static bool volatile bLoop = true;
static JavaVM *jvm = NULL;
static jobject nativeNotification;
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved )
{
return TRUE;
}
bool DoNativeCall(JNIEnv *env)
/****************************/
{
jclass cls = env->GetObjectClass(nativeNotification);
jmethodID callbackMethod = env->GetMethodID(cls, "nativeCallBack", "()V");
env->CallVoidMethod(nativeNotification, callbackMethod);
if ( env->ExceptionOccurred() )
{
env->ExceptionDescribe();
env->ExceptionClear();
printf("Native code got exception calling nativeCallBack\n");
return(false);
}
return(true);
}
DWORD WINAPI JNIThread( LPVOID lpParam )
/**************************************/
{
JNIEnv *env = NULL;
jvm->AttachCurrentThread((void**)&env,NULL);
SetEvent(hInitCompleteEvent);
while (bLoop)
{
if (!DoNativeCall(env))
{
bLoop = false;
}
Sleep(1);
}
env->DeleteGlobalRef(nativeNotification);
jvm->DetachCurrentThread();
return 0;
}
/*
* Class: JNITest
* Method: nativeInitialize
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_JNITest_nativeInitialize(JNIEnv *env, jobject object, jobject _nativeNotification)
/************************************************************************************************************/
{
DWORD dwThrdParam = 0;
env->GetJavaVM(&jvm);
nativeNotification = env->NewGlobalRef(_nativeNotification);
hInitCompleteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
hThread = CreateThread( NULL, 0, JNIThread, &dwThrdParam, 0, &dwThreadId );
if (hThread == NULL)
{
env->DeleteGlobalRef(nativeNotification);
return;
}
WaitForSingleObject(hInitCompleteEvent, INFINITE);
}