o/
i tried the googles but could not find information fitting my brain yet. maybe you guys can help me out.
until now the JNI adventures of mine were controlled by the host/java so threads where first spawned in java and i never had to fetch the JNIEnv from the VM. JNIEnv came from with the native call. now i started playing around with binding fmod to java.
fmod spawns a few threads when used, 4-5 (mixer, studio-update, async, stream, etc.). these threads do not see a JNIEnv when they start. there is also no way to queue code for me and care about “life-cycle”. when i hook up callbacks into those threads, fmod allows a few basic things like a system-callback (sometimes called form async c-thread) or dsp-processing-callbacks (called from mixer-c-thread) - i ran into something which i cannot get right. either i end up with a (small) memory leak or i get spammed by java-threads :
a system callback looks like this :
FMOD_RESULT __stdcall callback([...])
{
return FMOD_OK;
}
to access java i’m grabbing the JNIEnv from the VM, which i fetch when [icode]System.loadLibrary()[/icode] is called :
static JavaVM *jvm;
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
{
jvm = vm;
return JNI_VERSION_1_6;
}
back to the callback :
FMOD_RESULT __stdcall callback([...])
{
JNIEnv *jenv = (*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
// do things to java ...
(*jvm)->DetachCurrentThread(jvm);
return FMOD_OK;
}
i took a look into lwjgl 2.x code and found that this is similar to how the [icode]ARBDebugOutput[/icode] implementation works.
anyway, question is : does [icode]AttachCurrentThread[/icode] and [icode]DetachCurrentThread[/icode] use a reference counter ?
using this, assuming the JNIEnv reference count on that particular c-thread is zero, attaching creates a new java-thread (fair enough), and terminates it when detached (reference back to zero). calling that callback, say - every frame in the game loop, creates a new java-thread every time executed. which is … pretty bad.
so for now i simple do not detach, and live with a zombie java-thread, after the sound-system shuts down. usually you do not create more the 2 sound systems in a game anyway, but it can pile up to a nasty pack of zombies - after hot-swapping java code and restart the game-loop :
FMOD_RESULT __stdcall callback([...])
{
JNIEnv *jenv = (*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
// do things to java ...
// (*jvm)->DetachCurrentThread(jvm); // memleak
return FMOD_OK;
}
what is bugging me, when i track the java-threads used by [icode]ARBDebugOutput[/icode] callbacks i dont see the same behaviour. is that due to the JNIEnv reference, which is not zero when entering the method ? are calls caused by ARBDebugOutput actually coming from the gl-thread (which is known and attached to java) ? afaik it is async, or just deferred ?
for now i end up testing if attaching would be required at all :
FMOD_RESULT __stdcall callback([...])
{
int attached;
JNIEnv *jenv;
int env_status = (*jvm)->GetEnv(jvm, (void *)&jenv, JNI_VERSION_1_6);
if( env_status == JNI_EDETACHED )
{
(*jvm)->AttachCurrentThreadAsDaemon(jvm, (void **)&jenv, NULL);
attached = 1;
}
// do things to java ...
if ( attached )
{
// still nothing. :|
}
return FMOD_OK;
}
i tried getting rid of the zombie threads from within java, but could not find any way to do so. the attached java-thread is not willing to interrupt or anything else. that is still good enough tho’, zombies are not that dangerous and the callbacks work just fine.
- is there a way to tell the jvm to “reuse” threads when attaching a zero-reference c-thread (deattaching properly) ?
- is there a way to tell the jvm to cleanup jni-attached java-threads ?
- is this the right way to access java from c-threads ?
- did i miss something ?
thanks
o/