JNI Enhancements
|
JNI Documentation |
JNI has been enhanced in the Java 2 SDK to:
Changes to the JNI are made based on feedback from users . Please continue to send your comments, suggestions, and concerns to jni@java.sun.com.
#define JNI_VERSION_1_1 0x00010001 #define JNI_VERSION_1_2 0x00010002 /* Error codes */ #define JNI_EDETACHED (-2) /* thread detached from the VM */ #define JNI_EVERSION (-3) /* JNI version error */
FindClass
has been extended
so that it finds classes loaded with a class loader.
jclass FindClass(JNIEnv *env, const char *name);
In JDK 1.1,
FindClass
searched only local classes inCLASSPATH
. The resulting classes did not have a class loader.The Java security model has been extended to allow non-system classes to load and call native methods. In the Java 2 Platform,
FindClass
locates the class loader associated with the current native method. If the native code belongs to a system class, no class loader will be involved. Otherwise, the proper class loader will be invoked to load and link the named class.When
FindClass
is called through the Invocation Interface, there is no current native method or its associated class loader. In that case, the result ofClassLoader.getBaseClassLoader
is used. This is the class loader the virtual machine creates for applications, and is able to locate classes listed in thejava.class.path
property.
In the Java 2 SDK, each class loader manages its own set of native libraries.
The same JNI native library cannot be loaded into more than
one class loader. Doing so causes UnsatisfiedLinkError
to be thrown. For example, System.loadLibrary
throws an
UnsatisfiedLinkError
when used to load a native library
into two class loaders. The benefits of the new approach are:
To facilitate versioning control and resource management, JNI libraries in the Java 2 Platform may optionally export the following two functions:
jint JNI_OnLoad(JavaVM *vm, void *reserved);
The VM callsJNI_OnLoad
when the native library is loaded (for example, throughSystem.loadLibrary
).JNI_OnLoad
must return the JNI version needed by the native library.In order to use any of the new JNI functions, a native library must export a
JNI_OnLoad
function that returnsJNI_VERSION_1_2
. If the native library does not export aJNI_OnLoad
function, the VM assumes that the library only requires JNI versionJNI_VERSION_1_1
. If the VM does not recognize the version number returned byJNI_OnLoad
, the native library cannot be loaded.
void JNI_OnUnload(JavaVM *vm, void *reserved);
The VM calls JNI_OnUnload
when the class loader
containing the native library is garbage collected. This function can
be used to perform cleanup operations. Because this function is called
in an unknown context (such as from a finalizer), the programmer
should be conservative on using Java VM services, and refrain from
arbitrary Java call-backs.
Note that JNI_OnLoad
and JNI_OnUnload
are
two functions optionally supplied by JNI libraries, not exported from
the VM.
JDK 1.1 provides a DeleteLocalRef
function so that
programmers can manually delete local references. For example, if
native code iterates through a potentially large array of objects and
uses one element in each iteration, it is a good practice to delete
the local reference to the no-longer-used array element before a new
local reference is created in the next iteration.
The Java 2 SDK provides an additional set of functions for local reference lifetime management.
jint EnsureLocalCapacity(JNIEnv *env, jint capacity);
Ensures that at least a given number of local references can be created in the current thread. Returns 0 on success; otherwise returns a negative number and throws an
OutOfMemoryError
.Before it enters a native method, the VM automatically ensures that at least 16 local references can be created.
For backward compatibility, the VM allocates local references beyond the ensured capacity. (As a debugging support, the VM may give the user warnings that too many local references are being created. In the Java 2 SDK, the programmer can supply the
-verbose:jni
command line option to turn on these messages.) The VM callsFatalError
if no more local references can be created beyond the ensured capacity.
jint PushLocalFrame(JNIEnv *env, jint capacity);
Creates a new local reference frame, in which at least a given number of local references can be created. Returns 0 on success, a negative number and a pending
OutOfMemoryError
on failure.Note that local references already created in previous local frames are still valid in the current local frame.
jobject PopLocalFrame(JNIEnv *env, jobject result);
Pops off the current local reference frame, frees all the local references, and returns a local reference in the previous local reference frame for the given
result
object.Pass
NULL
asresult
if you do not need to return a reference to the previous frame.
jobject NewLocalRef(JNIEnv *env, jobject ref);
Creates a new local reference that refers to the same object asref
. The givenref
may be a global or local reference. ReturnsNULL
ifref
refers tonull
.
jboolean ExceptionCheck(JNIEnv *env);
ReturnsJNI_TRUE
when there is a pending exception; otherwise, returnsJNI_FALSE
.
NULL
. Programmers can detect
whether a weak global reference points to a freed object by using
IsSameObject
to compare the weak reference against
NULL
.
Weak global references in JNI are a simplified version of the Java
Weak References, available as part of the Java 2 Platform API (
java.lang.ref
package and its classes).
Clarification    (added June 2001)
Since garbage collection may occur while native methods are running, objects referred to by weak global references can be freed at any time. While weak global references can be used where global references are used, it is generally inappropriate to do so, as they may become functionally equivalent to
NULL
without notice.While
IsSameObject
can be used to determine whether a weak global reference refers to a freed object, it does not prevent the object from being freed immediately thereafter. Consequently, programmers may not rely on this check to determine whether a weak global reference may used (as a non-NULL
reference) in any future JNI function call.To overcome this inherent limitation, it is recommended that a standard (strong) local or global reference to the same object be acquired using the JNI functions
NewLocalRef
orNewGlobalRef
, and that this strong reference be used to access the intended object. These functions will returnNULL
if the object has been freed, and otherwise will return a strong reference (which will prevent the object from being freed). The new reference should be explicitly deleted when immediate access to the object is no longer required, allowing the object to be freed.The weak global reference is weaker than other types of weak references (Java objects of the SoftReference or WeakReference classes). A weak global reference to a specific object will not become functionally equivalent to
NULL
until after SoftReference or WeakReference objects referring to that same specific object have had their references cleared.The weak global reference is weaker than Java's internal references to objects requiring finalization. A weak global reference will not become functionally equivalent to
NULL
until after the completion of the the finalizer for the referenced object, if present.Interactions between weak global references and PhantomReferences are undefined. In particular, implementations of a Java VM may (or may not) process weak global references after PhantomReferences, and it may (or may not) be possible to use weak global references to hold on to objects which are also referred to by PhantomReference objects. This undefined use of weak global references should be avoided.
jweak NewWeakGlobalRef(JNIEnv *env, jobject obj);
Creates a new weak global reference. ReturnsNULL
ifobj
refers tonull
, or if the VM runs out of memory. If the VM runs out of memory, anOutOfMemoryError
will be thrown.
void DeleteWeakGlobalRef(JNIEnv *env, jweak obj);
Delete the VM resources needed for the given weak global reference.
In JDK 1.1, programmers can use
Get/Release
functions to
obtain a pointer to primitive array elements. If the VM supports
pinning, the pointer to the original data is returned; otherwise, a
copy is made.
New functions allow native code to obtain a direct pointer to array elements even if the VM does not support pinning.
void * GetPrimitiveArrayCritical(JNIEnv *env, jarray array, jboolean *isCopy);
void ReleasePrimitiveArrayCritical(JNIEnv *env, jarray array, void *carray, jint mode);
The semantics of these two functions are very similar to the existingGet/Release
functions. If possible, the VM returns a pointer to the primitive array; otherwise, a copy is made. However, there are significant restrictions on how these functions can be used.ArrayElements After calling
GetPrimitiveArrayCritical
, the native code should not run for an extended period of time before it callsReleasePrimitiveArrayCritical
. We must treat the code inside this pair of functions as running in a "critical region." Inside a critical region, native code must not call other JNI functions, or any system call that may cause the current thread to block and wait for another Java thread. (For example, the current thread must not callread
on a stream being written by another Java thread.)These restrictions make it more likely that the native code will obtain an uncopied version of the array, even if the VM does not support pinning. For example, a VM may temporarily disable garbage collection when the native code is holding a pointer to an array obtained via
GetPrimitiveArrayCritical
.Multiple pairs of
GetPrimtiveArrayCritical
andReleasePrimitiveArrayCritical
may be nested. For example:jint len = (*env)->GetArrayLength(env, arr1); jbyte *a1 = (*env)->GetPrimitiveArrayCritical(env, arr1, 0); jbyte *a2 = (*env)->GetPrimitiveArrayCritical(env, arr2, 0); /* We need to check in case the VM tried to make a copy. */ if (a1 == NULL || a2 == NULL) { ... /* out of memory exception thrown */ } memcpy(a1, a2, len); (*env)->ReleasePrimitiveArrayCritical(env, arr2, a2, 0); (*env)->ReleasePrimitiveArrayCritical(env, arr1, a1, 0);
Note that GetPrimitiveArrayCritical
might still make a copy
of the array if the VM internally represents arrays in a different format.
Therefore we need to check its return value against NULL
for
possible out of memory situations.
void GetStringRegion(JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf);
Copieslen
number of Unicode characters beginning at offsetstart
to the given bufferbuf
.Throws
StringIndexOutOfBoundsException
on index overflow.
<
void GetStringUTFRegion(JNIEnv *env, jstring str, jsize start, jsize len, char *buf);
Translateslen
number of Unicode characters beginning at offsetstart
into UTF-8 format and place the result in the given bufferbuf
.Throws
StringIndexOutOfBoundsException
on index overflow.
const jchar * GetStringCritical(JNIEnv *env, jstring string, jboolean *isCopy);
void ReleaseStringCritical(JNIEnv *env, jstring string, const jchar *carray);
The semantics of these two functions are similar to the existingGet/ReleaseStringChars
functions. If possible, the VM returns a pointer to string elements; otherwise, a copy is made. However, there are significant restrictions on how these functions can be used. In a code segment enclosed byGet/ReleaseStringCritical
calls, the native code must not issue arbitrary JNI calls, or cause the current thread to block.The restrictions on
Get/ReleaseStringCritical
are similar to those onGet/ReleasePrimitiveArrayCritical
.
Programmers can use the JNI to call Java methods or access Java fields if they know the name and type of the methods or fields. The Java Core Reflection API allows programmers to introspect Java classes at runtime. JNI provides a set of conversion functions between field and method IDs used in the JNI to field and method objects used in the Java Core Reflection API.
jmethodID FromReflectedMethod(JNIEnv *env, jobject method);
Converts ajava.lang.reflect.Method
orjava.lang.reflect.Constructor
object to a method ID.
jfieldID FromReflectedField(JNIEnv *env, jobject field);
Converts a java.lang.reflect.Field
to a field ID.
jobject ToReflectedMethod(JNIEnv *env, jclass cls,
jmethodID methodID);
Converts a method ID derived fromcls
to ajava.lang.reflect.Method
orjava.lang.reflect.Constructor
object.Throws
OutOfMemoryError
and returns 0 if fails.
jobject ToReflectedField(JNIEnv *env, jclass cls,
jfieldID fieldID);
Converts a field ID derived fromcls
to ajava.lang.reflect.Field
object.Throws
OutOfMemoryError
and returns 0 if fails.
jint JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args);
In JDK 1.1, the second argument toJNI_CreateJavaVM
is always a pointer toJNIEnv *
. The third argument is a pointer to a JDK 1.1 specific structure (JDK1_1InitArgs
). TheJDK1_1InitArgs
structure is clearly not designed to be portable on all VMs.In the Java 2 SDK, we introduce a standard VM initialization structure. Backward compatibility is preserved. If the VM initialization argument points to a
JDK1_1InitArgs
structure,JNI_CreateJavaVM
still returns the 1.1 version of JNI interface pointer. The VM returns the 1.2 version of JNI interface pointer if the third argument points to aJavaVMInitArgs
structure. UnlikeJDK1_1InitArgs
, which contains a fixed set of options,JavaVMInitArgs
uses option strings to encode arbitrary VM start up options.typedef struct JavaVMInitArgs { jint version; jint nOptions; JavaVMOption *options; jboolean ignoreUnrecognized; } JavaVMInitArgs;Theversion
field must be set toJNI_VERSION_1_2
. (In contrast, the version field inJDK1_1InitArgs
must be set toJNI_VERSION_1_1
.) Theoptions
field is an array of the following type:typedef struct JavaVMOption { char *optionString; void *extraInfo; } JavaVMOption;The size of the array is denoted by the nOptions field inJavaVMInitArgs
. IfignoreUnrecognized
isJNI_TRUE
,JNI_CreateJavaVM
ignore all unrecognized option strings that begin with "-X
" or "_
". IfignoreUnrecognized
isJNI_FALSE
,JNI_CreateJavaVM
returnsJNI_ERR
as soon as it encounters any unrecognized option strings. All Java VMs must recognize the following set of standard options:
optionString meaning -D<name>=<value>
Set a system property -verbose[:class|gc|jni]
Enable verbose output. The options can be followed by a comma-separated list of names indicating what kind of messages will be printed by the VM. For example, " -verbose:gc,class
" instructs the VM to print GC and class loading related messages. Standard names include:gc
,class
, andjni
. All nonstandard (VM-specific) names must begin with "X
".vfprintf
extraInfo
is a pointer to thevfprintf
hook.exit
extraInfo
is a pointer to theexit
hook.abort
extraInfo
is a pointer to theabort
hook.In addition, each VM implementation may support its own set of non-standard option strings. Non-standard option names must begin with "
-X
" or an underscore ("_
"). For example, the Java 2 SDK supports-Xms
and-Xmx
options to allow programmers specify the initial and maximum heap size. Options that begin with "-X
" are accessible from the "java
" command line.Here is the example code that creates a Java VM in the Java 2 SDK:
JavaVMInitArgs vm_args; JavaVMOption options[4]; options[0].optionString = "-Djava.compiler=NONE"; /* disable JIT */ options[1].optionString = "-Djava.class.path=c:\myclasses"; /* user classes */ options[2].optionString = "-Djava.library.path=c:\mylibs"; /* set native library path */ options[3].optionString = "-verbose:jni"; /* print JNI-related messages */ vm_args.version = JNI_VERSION_1_2; vm_args.options = options; vm_args.nOptions = 4; vm_args.ignoreUnrecognized = TRUE; /* Note that in the Java 2 SDK, there is no longer any need to call * JNI_GetDefaultJavaVMInitArgs. */ res = JNI_CreateJavaVM(&vm, (void **)&env, &vm_args); if (res < 0) ...The Java 2 SDK still supports
JDK1_1InitArgs
in exactly the same way as JDK 1.1.
jint AttachCurrentThread(JavaVM *vm, void **penv, void *args);
In JDK 1.1, the second argument toAttachCurrentThread
is always a pointer toJNIEnv
. The third argument toAttachCurrentThread
was reserved, and should be set toNULL
.In the Java 2 SDK, you pass
NULL
as the third argument for 1.1 behavior, or pass a pointer to the following structure to specify additional information:typedef struct JavaVMAttachArgs { jint version; /* must be JNI_VERSION_1_2 */ char *name; /* the name of the thread, or NULL */ jobject group; /* global ref of a ThreadGroup object, or NULL */ } JavaVMAttachArgs;
jint DetachCurrentThread(JavaVM *vm);
In JDK 1.1, the main thread cannot be detached from the VM. It must callDestroyJavaVM
to unload the entire VM.In the Java 2 SDK, the main thread can be detached from the VM.
jint DestroyJavaVM(JavaVM *vm);
The support forDestroyJavaVM
was not complete in 1.1. Only the main thread may callDestroyJavaVM
. In the Java 2 SDK, any thread, whether attached or not, can call this function. If the current thread is attached, the VM waits until the current thread is the only user-level Java thread. If the current thread is not attached, the VM attaches the current thread and then waits until the current thread is the only user-level thread. The Java 2 SDK still does not support VM unloading, however.DestroyJavaVM
always returns an error code.
jint GetEnv(JavaVM *vm, void **env, jint version);
If the current thread is not attached to the VM, sets*env
toNULL
, and returnsJNI_EDETACHED
. If the specified version is not supported, sets*env
toNULL
, and returnsJNI_EVERSION
. Otherwise, sets*env
to the appropriate interface, and returnsJNI_OK
.
Copyright © 1995-99
Sun Microsystems, Inc.
All Rights Reserved.
Please send comments to: jni@java.sun.com |
|