cached jclass points to invalid object

640 views
Skip to first unread message

doteater

unread,
Jan 10, 2011, 10:44:38 AM1/10/11
to android-ndk
Following the code from here (http://java.sun.com/docs/books/jni/html/
other.html), I've constructed my JNI_OnLoad function in the same
manner:

JavaVM* g_jvm = 0;
jclass g_jniClass;
jmethodID g_jniCallback;

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved)
{
JNIEnv* env;
jclass jcls;
g_jvm = jvm;

// Check JNI support
if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4))
return JNI_ERR;

jcls = (jclass)(*env)->FindClass(env, "JNIInterface");
if (jcls == NULL)
return JNI_ERR;

g_jniClass = (jclass)(*env)->NewWeakGlobalRef(env, jcls);
if (g_jniClass == NULL)
return JNI_ERR;

g_jniCallback = (jmethodID)(*env)->GetStaticMethodID(env, jcls, "g",
"()V");
if (g_jniCallback == NULL)
return JNI_ERR;

LOG_INFO("JNI_OnLoad completed!");

return JNI_VERSION_1_4;
}

JNI_OnLoad seems to run through correctly as I get the "JNI_OnLoad
completed!" in the LogCat. Later on, in another jni function I try to
invoke the callback using the cached jclass with this call:

JNIEXPORT void JNICALL callbackTest(JNIEnv *env, jobject obj)
{
(*env)->CallStaticVoidMethod(env, g_jniClass, g_jniCallback);
}

which results in the warning:

JNI WARNING: jclass points to invalid object 0xde5e3ff7

and the app crashes afterwards. Is it not possible to cache a jclass,
as this article seems to suggest (http://android.wooyd.org/
JNIExample/)? Or am I perhaps invoking the callback incorrectly?

Mike Edenfield

unread,
Jan 10, 2011, 2:20:20 PM1/10/11
to andro...@googlegroups.com, doteater
On 1/10/2011 10:44 AM, doteater wrote:
> Following the code from here (http://java.sun.com/docs/books/jni/html/
> other.html), I've constructed my JNI_OnLoad function in the same
> manner:
> g_jniClass = (jclass)(*env)->NewWeakGlobalRef(env, jcls);
> if (g_jniClass == NULL)
> return JNI_ERR;

Don't use a weak global reference here, as it doesn't really do what you
want. The VM is still allowed to garbage-collect the underlying jclass
object if there are only weak references to it. They're mostly used if
you want to get a global reference to something that you know is
referenced elsewhere, or if you're willing to deal with the possibility
that it might go away (by checking IsSameObject).

A normal global reference will force the VM to maintain the jclass
object you got back until you explicitly destroy the reference, making
it valid for the rest of your application.

http://download.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.html#weak

--Mike

alan

unread,
Jan 11, 2011, 4:28:43 AM1/11/11
to android-ndk
also note early versions of android dont support weak references,
before using the value stored in a weak reference you must create a
local reference to the stored object then check that the object is
still valid. For caching a class a strong global reference is
definitely more appropriate
> http://download.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions...
>
> --Mike

doteater

unread,
Jan 11, 2011, 8:19:47 AM1/11/11
to android-ndk
Thanks for the help. Making it a global referenced worked. Is it
then safe to create and delete this reference in JNI_OnLoad and
JNI_OnUnload? The JNI Programmer's Guide and Specification mentions
(regarding caching a class 'c' via weak global reference):

A global reference would keep C alive, which in turn would keep C's
class loader alive. Given that the native library is associated with
C's class loader L, the native library would not be unloaded and
JNI_OnUnload would not be called.

Does this warning apply if my library is statically loaded in the
class that I'm caching? i.e.:

class JNIInterface
{
public static void g() { /* this method is cached in JNI_OnLoad
*/ }

public static native void nativeFunction0();
public static native void nativeFunction1();
// etc.

static {
System.loadLibrary("mylibrary");

fadden

unread,
Jan 11, 2011, 8:02:37 PM1/11/11
to android-ndk
On Jan 10, 7:44 am, doteater <derek.a.t...@gmail.com> wrote:
> JNI_OnLoad seems to run through correctly as I get the "JNI_OnLoad
> completed!" in the LogCat.  Later on, in another jni function I try to
> invoke the callback using the cached jclass with this call:
>
> JNIEXPORT void JNICALL callbackTest(JNIEnv *env, jobject obj)
> {
>         (*env)->CallStaticVoidMethod(env, g_jniClass, g_jniCallback);
>
> }

The "JNI Tips" document says the following:

* "Weak global" references are implemented, but may only be passed to
NewLocalRef, NewGlobalRef, and DeleteWeakGlobalRef. (The spec strongly
encourages programmers to create hard references to weak globals
before doing anything with them, so this should not be at all
limiting.)

> and the app crashes afterwards.  Is it not possible to cache a jclass,
> as this article seems to suggest (http://android.wooyd.org/
> JNIExample/)?  Or am I perhaps invoking the callback incorrectly?

See:
http://groups.google.com/group/android-ndk/browse_thread/thread/618ff83dd88694b/2f54e5969a832a63?lnk=gst&q=wooyd#2f54e5969a832a63

fadden

unread,
Jan 11, 2011, 8:08:53 PM1/11/11
to android-ndk
On Jan 11, 5:19 am, doteater <derek.a.t...@gmail.com> wrote:
> Thanks for the help.  Making it a global referenced worked.  Is it
> then safe to create and delete this reference in JNI_OnLoad and
> JNI_OnUnload?  The JNI Programmer's Guide and Specification mentions
> (regarding caching a class 'c' via weak global reference):
>
> A global reference would keep C alive, which in turn would keep C's
> class loader alive. Given that the native library is associated with
> C's class loader L, the native library would not be unloaded and
> JNI_OnUnload would not be called.

If this is a concern you can use weak-global references; just convert
them to locals before you try to use them. However:

(1) No class unloading can occur unless ALL classes associated with a
class loader can be discarded. In other words, if the app framework
has no references to anything related to your app. The Android app
framework doesn't work this way -- it's much more efficient to just
kill the whole process if the app isn't needed any more.

(2) No shipping version of Dalvik unloads classes. JNI_OnUnload is
never called. This may change in the future, however.
Reply all
Reply to author
Forward
0 new messages