Advanced ndk topics

Click here to load reader

download Advanced ndk topics

of 19

description

 

Transcript of Advanced ndk topics

  • 1. Local Global references Design Considerations Based on http://www.uni- ulm.de/fileadmin/website_uni_ulm/iui.inst. 200/files/staff/domaschka/misc/jni_progra mmers_guide_spec.pdf JNI Advanced Topics

2. Opaque References Instance and array types (such as jobject, jclass, jstring and jarray) are opaque references. Native code never directly inspects the contents of an opaque reference pointer. Instead it uses JNI functions to access the data structure pointed to by an opaque reference. By only dealing with opaque references, No knowledge about internal object layout that is dependent upon a particular Java virtual machine implementation. 3. Local and global references have different lifetimes. Local references are automatically freed, whereas global and weak global references remain valid until they are freed by the programmer. A local or global reference keeps the referenced object from being garbage collected. A weak global reference, on the other hand, allows the referenced object to be garbage collected. Not all references can be used in all contexts. It is illegal, for example, to use a local reference after the native method that created the reference returns 4. Local References Most JNI functions create local references. For example, the JNI function New-Object creates a new instance and returns a local reference to that instance. A local reference is valid only within the dynamic context of the native method that creates it, and only within that one invocation of the native method. All local references created during the execution of a native method will be freed once the native method returns. In Android there is a local reference table till 512 entries used for all native methods, standard violation You must not write native methods that store a local reference in a static variable and expect to use the same reference in subsequent invocations. 5. Code part /* This code is illegal */ jstring MyNewString(JNIEnv *env, jchar *chars, jint len) { static jclass stringClass = NULL; if (stringClass == NULL) { stringClass = (*env)->FindClass(env, "java/lang/String"); } /* It is wrong to use the cached stringClass here, because it may be invalid. */ cid = (*env)->GetMethodID(env, stringClass, "", "([C)V"); ... 6. Local Reference Invalidation There are two ways to invalidate a local reference. 1. Virtual machine automatically frees all local references created during the execution of a native method after the native method returns. 2. Programmers may explicitly manage the lifetime of local references using JNI functions such as DeleteLocalRef. 7. Memory Leaks Why do you want to delete local references explicitly if the virtual machine automatically frees them after native methods return? A local reference keeps the referenced object from being garbage collected until the local reference is invalidated. Otherwise the virtual machine will only be able to free the pointed object after the native method returns. 8. Threads Local references are also only valid in the thread that creates them. A local reference that is created in one thread cannot be used in another thread. It is a programming error for a native method to store a local reference in a global variable and expect another thread to use the local reference. 9. Global References You can use a global reference across multiple invocations of a native method. A global reference can be used across multiple threads and remains valid until it is freed by the programmer. Like a local reference, a global reference ensures that the referenced object will not be garbage collected. 10. Global References Unlike local references, which are created by most JNI functions, global references are created by just one JNI function, NewGlobalRef. The following version of MyNewString illustrates how to use a global reference. We highlight the differences between the code below and the code that mistakenly cached a local reference in the last section: 11. Code jstring MyNewString(JNIEnv *env, jchar *chars, jint len) { static jclass stringClass = NULL; ... /* Create a global reference */ stringClass = (*env)->NewGlobalRef(env, localRefCls); /* The local reference is no longer useful */ (*env)->DeleteLocalRef(env, localRefCls); } ... } 12. Global References The modified version passes the local reference returned from FindClass to NewGlobalRef, which creates a global reference to the java.lang.String class object. We check whether the NewGlobalRef has successfully created string- class after deleting localRefCls because the local reference localRefCls needs to be deleted in either case. 13. Comparing References Given two local, global, or weak global references, you can check whether they refer to the same object using the IsSameObject function. For example: (*env)->IsSameObject(env, obj1, obj2) Returns JNI_TRUE (or 1) if obj1 and obj2 refer to the same object, and returns JNI_FALSE (or 0) otherwise. A NULL reference in JNI refers to the null object in the Java virtual machine. If obj is a local or a global reference, you may use either (*env)->IsSameObject(env, obj, NULL) or obj == NULL 14. Freeing Local References You need to create a large number of local references in a single native method invocation Your native method does not return at all. For example, a native method may enter an infinite event dispatch loop. 15. Ensure Local Capacity The JNI specification dictates that the virtual machine automatically ensures that each native method can create at least 16 local references. Experience shows that this provides enough capacity for the majority of native methods that do not contain complex interactions with objects in the Java virtual machine. If, however, there is a need to create additional local references, a native method may issue an EnsureLocalCapacity call to make sure that space for a sufficient number of local references is available 16. Ensure Capacity /* The number of local references to be created is equal to the length of the array. */ if ((*env)->EnsureLocalCapacity(env, len)) < 0) { ... /* out of memory */ } 17. Push/Pop Alternatively, the Push/PopLocalFrame functions allow programmers to create nested scopes of local references. For example, we may also rewrite the same example as follows: #define N_REFS ... /* the maximum number of local references used in each iteration */ for (i = 0; i < len; i++) { if ((*env)->PushLocalFrame(env, N_REFS) < 0) { ... /* out of memory */ } jstr = (*env)->GetObjectArrayElement(env, arr, i); ... /* process jstr */ (*env)->PopLocalFrame(env, NULL); } PushLocalFrame creates a new scope for specific number of local references. PopLocalFrame destroys the topmost scope, freeing all local references in that scope. 18. Rules When a utility function that returns a primitive type is called, it must not have the side effect of accumulating additional local, global, or weak global references. When a utility function that returns a reference type is called, it must not accumulate extra local, global, or weak global references, other than the reference it returns as result. 19. General Design Rules Keep the boundaries simple. Complex control flow that goes back and forth between the Java virtual machine and native code can be hard to debug and maintain. Keep the code on the native code side minimal. There are compelling reasons to do so. Native code is neither portable nor type-safe. Error checking in native code is tedious. It is good software engineering to keep such parts to a minimum. Keep native code isolated. In practice, this could mean that all native methods are in the same package or in the same class, isolated from the rest of the application. The package or the class containing native methods essentially becomes the porting layer for the application. Dont do Java programming in native code