The Invocation API

翻譯自https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/invocation.html

Chapter   5

The Invocation API allows software vendors to load the Java VM into an arbitrary native application. Vendors can deliver Java-enabled applications without having to link with the Java VM source code.

Invocation API允許軟件供應商將Java VM加載到任意本地應用程序中。 供應商可以交付支持Java的應用程序,而無需鏈接Java VM源代碼。

本章從Invocation API的概述開始。 隨後是所有Invocation API函數的參考頁。

Overview

The following code example illustrates how to use functions in the Invocation API. In this example, the C++ code creates a Java VM and invokes a static method, called Main.test. For clarity, we omit error checking.

以下代碼示例說明了如何使用Invocation API中的函數。 在此示例中,C ++代碼創建一個Java VM,並調用一個名爲Main.test的靜態方法。 爲了清楚起見,我們省略了錯誤檢查。

#include <jni.h>       /* where everything is defined */
    ...
    JavaVM *jvm;       /* denotes a Java VM */
    JNIEnv *env;       /* pointer to native method interface */
    JavaVMInitArgs vm_args; /* JDK/JRE 6 VM initialization arguments */
    JavaVMOption* options = new JavaVMOption[1];
    options[0].optionString = "-Djava.class.path=/usr/lib/java";
    vm_args.version = JNI_VERSION_1_6;
    vm_args.nOptions = 1;
    vm_args.options = options;
    vm_args.ignoreUnrecognized = false;
    /* load and initialize a Java VM, return a JNI interface
     * pointer in env */
    JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
    delete options;
    /* invoke the Main.test method using the JNI */
    jclass cls = env->FindClass("Main");
    jmethodID mid = env->GetStaticMethodID(cls, "test", "(I)V");
    env->CallStaticVoidMethod(cls, mid, 100);
    /* We are done. */
    jvm->DestroyJavaVM();
    

This example uses three functions in the API. The Invocation API allows a native application to use the JNI interface pointer to access VM features. The design is similar to Netscape’s JRI Embedding Interface.

本示例在API中使用三個函數。 Invocation API允許本地應用程序使用JNI接口指針來訪問VM功能。 該設計類似於Netscape的JRI嵌入接口。

Creating the VM

The JNI_CreateJavaVM() function loads and initializes a Java VM and returns a pointer to the JNI interface pointer. The thread that called JNI_CreateJavaVM() is considered to be the main thread.

JNI_CreateJavaVM()函數加載並初始化Java VM,並返回指向JNI接口指針的指針。 調用JNI_CreateJavaVM()的線程被視爲主線程。

Attaching to the VM

The JNI interface pointer (JNIEnv) is valid only in the current thread. Should another thread need to access the Java VM, it must first call AttachCurrentThread() to attach itself to the VM and obtain a JNI interface pointer. Once attached to the VM, a native thread works just like an ordinary Java thread running inside a native method. The native thread remains attached to the VM until it calls DetachCurrentThread() to detach itself.

JNI接口指針(JNIEnv)僅在當前線程中有效。 如果另一個線程需要訪問Java VM,則必須首先調用AttachCurrentThread()將其自身依附到VM並獲取JNI接口指針。 一旦依附到VM,本地線程就可以像在本地方法中運行的普通Java線程一樣工作。 本地線程將保持與VM的連接,直到它調用DetachCurrentThread()使其脫離。

The attached thread should have enough stack space to perform a reasonable amount of work. The allocation of stack space per thread is operating system-specific. For example, using pthreads, the stack size can be specified in the pthread_attr_t argument to pthread_create.
附着線程應具有足夠的堆棧空間以執行合理的工作量。 每個線程的堆棧空間分配是特定於操作系統的。 例如,使用pthreads,可以在pthread_create的pthread_attr_t參數中指定堆棧大小。

Detaching from the VM

A native thread attached to the VM must call DetachCurrentThread() to detach itself before exiting. A thread cannot detach itself if there are Java methods on the call stack.

附着到VM的本地線程必須在退出之前調用DetachCurrentThread()使其自身分離。 如果調用堆棧上有Java方法,則線程無法自行分離。

Unloading the VM

The JNI_DestroyJavaVM() function unloads a Java VM. As of JDK/JRE 1.1, only the main thread could unload the VM, by calling DestroyJavaVM. As of JDK/JRE 1.2, the restriction was removed, and any thread may call DestroyJavaVM to unload the VM.

JNI_DestroyJavaVM()函數卸載Java VM。 在JDK / JRE 1.1中,只有主線程可以通過調用DestroyJavaVM卸載VM。 從JDK / JRE 1.2開始,該限制已刪除,任何線程都可以調用DestroyJavaVM來卸載VM。

The VM waits until the current thread is the only non-daemon user thread before it actually unloads. User threads include both Java threads and attached native threads. This restriction exists because a Java thread or attached native thread may be holding system resources, such as locks, windows, and so on. The VM cannot automatically free these resources. By restricting the current thread to be the only running thread when the VM is unloaded, the burden of releasing system resources held by arbitrary threads is on the programmer.


VM將等待直到當前線程是唯一的非守護程序用戶線程,然後才實際卸載。 用戶線程包括Java線程和附着的本地線程。 之所以存在此限制,是因爲Java線程或附着的本地線程可能正在持有系統資源,例如鎖,窗口等。 VM無法自動釋放這些資源。 通過在卸載VM時將當前線程限制爲唯一正在運行的線程,釋放由任意線程持有的系統資源的後果由程序員承擔。

Library and Version Management

As of JDK/JRE 1.1, once a native library is loaded, it is visible from all class loaders. Therefore two classes in different class loaders may link with the same native method. This leads to two problems:

從JDK / JRE 1.1開始,一旦加載了本地庫,就可以在所有類加載器中看到它。因此,兩個不同的類加載器可能使用相同的本地方法鏈接。這導致兩個問題:

  • A class may mistakenly link with native libraries loaded by a class with the same name in a different class loader.
  •  一個類可能會錯誤地鏈接到被一個不同的類加載器中的同名類加載的本地庫。
  • Native methods can easily mix classes from different class loaders. This breaks the name space separation offered by class loaders, and leads to type safety problems.
  •  本地方法可以輕鬆地混合使用來自不同類加載器的類。這打破了類加載器提供的命名空間分隔,並導致類型安全問題。

As of JDK/JRE 1.2, 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:

從JDK / JRE 1.2開始,每個類加載器都管理自己的本地庫組。同一JNI本地庫不能被加載到多個類加載器中。這樣做會引發UnsatisfiedLinkError。例如,當System.loadLibrary被用於將本地庫加載到兩個類加載器中時,拋出UnsatisfiedLinkError。新方法的好處是:

  • Name space separation based on class loaders is preserved in native libraries. A native library cannot easily mix classes from different class loaders.
  • In addition, native libraries can be unloaded when their corresponding class loaders are garbage collected.
  • 基於類加載器的命名空間隔離保留在本地庫中。本地庫無法輕鬆地混合使用來自不同類加載器的類。
  • 另外,當本地庫的相應類加載器被垃圾回收時,它們可以被卸載。

To facilitate version control and resource management, JNI libraries as of JDK/JRE 1.2 optionally export the following two functions:
爲了促進版本控制和資源管理,從JDK / JRE 1.2開始的JNI庫可以選擇導出以下兩個函數:

JNI_OnLoad

jint JNI_OnLoad(JavaVM *vm, void *reserved);

The VM calls JNI_OnLoad when the native library is loaded (for example, through System.loadLibrary). JNI_OnLoad must return the JNI version needed by the native library.

加載本地庫時(例如,通過System.loadLibrary),VM調用JNI_OnLoad。 JNI_OnLoad必須返回本地庫所需的JNI版本。

In order to use any of the new JNI functions, a native library must export a JNI_OnLoad function that returns JNI_VERSION_1_2. If the native library does not export a JNI_OnLoad function, the VM assumes that the library only requires JNI version JNI_VERSION_1_1. If the VM does not recognize the version number returned by JNI_OnLoad, the native library cannot be loaded.

爲了使用任何新的JNI函數,本地庫必須導出返回JNI_VERSION_1_2的JNI_OnLoad函數。 如果本地庫未導出JNI_OnLoad函數,則VM假定該庫僅需要JNI版本JNI_VERSION_1_1。 如果VM無法識別JNI_OnLoad返回的版本號,則無法加載本地庫。

LINKAGE:

Exported from native libraries that contain native method implementation.

從包含本地方法實現的本地庫中導出。

SINCE:

JDK/JRE 1.4

In order to use the JNI functions introduced in J2SE release 1.2, in addition to those that were available in JDK/JRE 1.1, a native library must export a JNI_OnLoad function that returns JNI_VERSION_1_2.

爲了使用J2SE 1.2版中引入的JNI函數,除了JDK / JRE 1.1中可用的那些函數外,本地庫還必須導出返回JNI_VERSION_1_2的JNI_OnLoad函數。

In order to use the JNI functions introduced in J2SE release 1.4, in addition to those that were available in release 1.2, a native library must export a JNI_OnLoad function that returns JNI_VERSION_1_4.
爲了使用J2SE 1.4版中引入的JNI函數,除了1.2版中可用的那些函數外,本地庫還必須導出返回JNI_VERSION_1_4的JNI_OnLoad函數。

If the native library does not export a JNI_OnLoad function, the VM assumes that the library only requires JNI version JNI_VERSION_1_1. If the VM does not recognize the version number returned by JNI_OnLoad, the native library cannot be loaded.
如果本地庫未導出JNI_OnLoad函數,則VM假定該庫僅需要JNI版本JNI_VERSION_1_1。 如果VM無法識別JNI_OnLoad返回的版本號,則無法加載本地庫。

JNI_OnUnload

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.

當包含本地庫的類加載器被垃圾回收時,VM會調用JNI_OnUnload。 此功能可用於執行清理操作。 由於此函數是在未知上下文中(例如,從終結器中)調用的,因此程序員在使用Java VM服務時應保持保守,並避免進行任意Java回調。

Note that JNI_OnLoad and JNI_OnUnload are two functions optionally supplied by JNI libraries, not exported from the VM.
請注意,JNI_OnLoad和JNI_OnUnload是JNI庫可選提供的兩個函數,而不是從VM導出的。

LINKAGE:

Exported from native libraries that contain native method implementation.

從包含本地方法實現的本地庫中導出。

Invocation API Functions

The JavaVM type is a pointer to the Invocation API function table. The following code example shows this function table.

JavaVM是指向Invocation API函數表的指針。下列代碼展示了這個函數表。

typedef const struct JNIInvokeInterface *JavaVM;


const struct JNIInvokeInterface ... = {
    NULL,
    NULL,
    NULL,

    DestroyJavaVM,
    AttachCurrentThread,
    DetachCurrentThread,

    GetEnv,

    AttachCurrentThreadAsDaemon
};

 

Note that three Invocation API functions, JNI_GetDefaultJavaVMInitArgs(), JNI_GetCreatedJavaVMs(), and JNI_CreateJavaVM(), are not part of the JavaVM function table. These functions can be used without a preexisting JavaVM structure.

請注意,三個Invocation API函數JNI_GetDefaultJavaVMInitArgs(),JNI_GetCreatedJavaVMs()和JNI_CreateJavaVM()不在JavaVM函數表中。 可以在沒有預先存在的JavaVM結構的情況下使用這些函數。

JNI_GetDefaultJavaVMInitArgs

jint JNI_GetDefaultJavaVMInitArgs(void *vm_args);

Returns a default configuration for the Java VM. Before calling this function, native code must set the vm_args->version field to the JNI version it expects the VM to support. After this function returns, vm_args->version will be set to the actual JNI version the VM supports.

返回Java VM的默認配置。 在調用此函數之前,本地代碼必須將vm_args-> version字段設置爲期望VM支持的JNI版本。 該函數返回後,vm_args-> version將被設置爲VM支持的實際JNI版本。

LINKAGE:

Exported from the native library that implements the Java virtual machine.

PARAMETERS:

vm_args: a pointer to a JavaVMInitArgs structure in to which the default arguments are filled.

RETURNS:

Returns JNI_OK if the requested version is supported; returns a JNI error code (a negative number) if the requested version is not supported.

JNI_GetCreatedJavaVMs

jint JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen, jsize *nVMs);

Returns all Java VMs that have been created. Pointers to VMs are written in the buffer vmBuf in the order they are created. At most bufLen number of entries will be written. The total number of created VMs is returned in *nVMs.

返回所有已創建的Java VM。 指向VM的指針按照創建順序寫入緩衝區vmBuf中。 最多將寫入bufLen個條目。 在* nVMs中返回創建的VM總數。

As of JDK/JRE 1.2, creation of multiple VMs in a single process is not supported.

從JDK/JRE 1.2開始,不支持在一個進程中創建多個VM。

LINKAGE:

Exported from the native library that implements the Java virtual machine.

PARAMETERS:

vmBuf: pointer to the buffer where the VM structures will be placed.

bufLen: the length of the buffer.

nVMs: a pointer to an integer.

RETURNS:

Returns JNI_OK on success; returns a suitable JNI error code (a negative number) on failure.

JNI_CreateJavaVM

jint JNI_CreateJavaVM(JavaVM **p_vm, void **p_env, void *vm_args);

Loads and initializes a Java VM. The current thread becomes the main thread. Sets the env argument to the JNI interface pointer of the main thread.

加載並初始化Java VM。 當前線程成爲主線程。 將env參數設置爲主線程的JNI接口指針。

As of JDK/JRE 1.2 , creation of multiple VMs in a single process is not supported.

從JDK / JRE 1.2開始,不支持在單個進程中創建多個VM。

The second argument to JNI_CreateJavaVM is always a pointer to JNIEnv *, while the third argument is a pointer to a JavaVMInitArgs structure which uses option strings to encode arbitrary VM start up options:
JNI_CreateJavaVM的第二個參數始終是指向JNIEnv *的指針,而第三個參數是指向JavaVMInitArgs結構的指針,該結構使用可選的字符串編碼任意VM啓動選項:

typedef struct JavaVMInitArgs {
    jint version;

    jint nOptions;
    JavaVMOption *options;
    jboolean ignoreUnrecognized;
} JavaVMInitArgs;

The version field must be set to at least JNI_VERSION_1_2. The options field is an array of the following type:

typedef struct JavaVMOption {
    char *optionString;  /* the option as a string in the default platform encoding */
    void *extraInfo;
} JavaVMOption;

The size of the array is denoted by the nOptions field in JavaVMInitArgs. If ignoreUnrecognized is JNI_TRUE, JNI_CreateJavaVM ignore all unrecognized option strings that begin with "-X" or "_". If ignoreUnrecognized is JNI_FALSE, JNI_CreateJavaVM returns JNI_ERR as soon as it encounters any unrecognized option strings. All Java VMs must recognize the following set of standard options:

數組的大小由JavaVMInitArgs中的nOptions字段表示。 如果ignoreUnrecognized爲JNI_TRUE,則JNI_CreateJavaVM會忽略所有以“ -X”或“ _”開頭的無法識別的選項字符串。 如果ignoreUnrecognized爲JNI_FALSE,則JNI_CreateJavaVM在遇到任何無法識別的選項字符串時將立即返回JNI_ERR。 所有Java VM必須識別以下標準選項集:

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, and jni. All nonstandard (VM-specific) names must begin with "X".
vfprintf extraInfo is a pointer to the vfprintf hook.
exit extraInfo is a pointer to the exit hook.
abort extraInfo is a pointer to the abort 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 JDK/JRE 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.

另外,每個VM實現都可以支持其自己的一組非標準選項字符串。 非標準選項名稱必須以“ -X”或下劃線(“ _”)開頭。 例如,JDK / JRE支持-Xms和-Xmx選項,以允許程序員指定初始堆大小和最大堆大小。 可從“ java”命令行訪問以“ -X”開頭的選項。

Here is the example code that creates a Java VM in the JDK/JRE:
以下是在JDK / JRE中創建Java VM的示例代碼:

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 JDK/JRE, there is no longer any need to call
 * JNI_GetDefaultJavaVMInitArgs.
 */
res = JNI_CreateJavaVM(&vm, (void **)&env, &vm_args);
if (res < 0) ...

LINKAGE:

Exported from the native library that implements the Java virtual machine.

PARAMETERS:

p_vm: pointer to the location where the resulting VM structure will be placed.

p_env: pointer to the location where the JNI interface pointer for the main thread will be placed.

vm_args: Java VM initialization arguments.

RETURNS:

Returns JNI_OK on success; returns a suitable JNI error code (a negative number) on failure.

DestroyJavaVM

jint DestroyJavaVM(JavaVM *vm);

Unloads a Java VM and reclaims its resources.

卸載Java VM並回收其資源。

The support for DestroyJavaVM was not complete in JDK/JRE 1.1. As of JDK/JRE 1.1 Only the main thread may call DestroyJavaVM. Since JDK/JRE 1.2, 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 non-daemon 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 non-daemon user-level thread. The JDK/JRE still does not support VM unloading, however.

在JDK / JRE 1.1中,對DestroyJavaVM的支持不完整。 從JDK / JRE 1.1開始,只有主線程可以調用DestroyJavaVM。 從JDK / JRE 1.2開始,任何線程(無論是否連接)都可以調用此函數。 如果當前線程處於連接狀態,則VM會等待直到當前線程是唯一的非守護程序用戶級Java線程。 如果未附加當前線程,則VM會連接當前線程,然後等待直到當前線程是唯一的非守護程序用戶級線程。 但是,JDK / JRE仍然不支持VM卸載。

LINKAGE:

Index 3 in the JavaVM interface function table.

PARAMETERS:

vm: the Java VM that will be destroyed.

RETURNS:

Returns JNI_OK on success; returns a suitable JNI error code (a negative number) on failure.

As of JDK/JRE 1.1.2 unloading of the VM is not supported.

AttachCurrentThread

jint AttachCurrentThread(JavaVM *vm, void **p_env, void *thr_args);

Attaches the current thread to a Java VM. Returns a JNI interface pointer in the JNIEnv argument.

Trying to attach a thread that is already attached is a no-op.

A native thread cannot be attached simultaneously to two Java VMs.

When a thread is attached to the VM, the context class loader is the bootstrap loader.

將當前線程附着到Java VM。 在JNIEnv參數中返回JNI接口指針。

嘗試附着已連接的線程是一項禁忌措施。

本地線程不能同時附着到兩個Java VM。

將線程附加到VM時,上下文類加載器就是引導加載器 bootstrap loader。

LINKAGE:

Index 4 in the JavaVM interface function table.

PARAMETERS:

vm: the VM to which the current thread will be attached.

p_env: pointer to the location where the JNI interface pointer of the current thread will be placed.

thr_args: can be NULL or a pointer to a JavaVMAttachArgs structure to specify additional information:

As of JDK/JRE 1.1, the second argument to AttachCurrentThread is always a pointer to JNIEnv. The third argument to AttachCurrentThread was reserved, and should be set to NULL.

從JDK / JRE 1.1開始,AttachCurrentThread的第二個參數始終是指向JNIEnv的指針。 AttachCurrentThread的第三個參數已保留,應設置爲NULL。

As of JDK/JRE 1.2, you pass NULL as the third argument for 1.1 behavior, or pass a pointer to the following structure to specify additional information:

從JDK / JRE 1.2開始,第三個參數 傳遞NULL作爲1.1的行爲,或傳遞以下結構體的指針來指定額外信息:

typedef struct JavaVMAttachArgs {
    jint version;  /* must be at least JNI_VERSION_1_2 */
    char *name;    /* the name of the thread as a modified UTF-8 string, or NULL */
    jobject group; /* global ref of a ThreadGroup object, or NULL */
} JavaVMAttachArgs

RETURNS:

Returns JNI_OK on success; returns a suitable JNI error code (a negative number) on failure.

AttachCurrentThreadAsDaemon

jint AttachCurrentThreadAsDaemon(JavaVM* vm, void** penv, void* args);

Same semantics as AttachCurrentThread, but the newly-created java.lang.Thread instance is a daemon.

語義與AttachCurrentThread相同,但是新創建的java.lang.Thread實例是一個守護程序。

If the thread has already been attached via either AttachCurrentThread or AttachCurrentThreadAsDaemon, this routine simply sets the value pointed to by penv to the JNIEnv of the current thread. In this case neither AttachCurrentThread nor this routine have any effect on the daemon status of the thread.
如果線程已經通過AttachCurrentThread或AttachCurrentThreadAsDaemon附着,則該例程將penv指向的值簡單地設置爲當前線程的JNIEnv。 在這種情況下,AttachCurrentThread和此例程都不會對線程的守護程序狀態產生任何影響。

LINKAGE:

Index 7 in the JavaVM interface function table.

PARAMETERS:

vm: the virtual machine instance to which the current thread will be attached.

penv: a pointer to the location in which the JNIEnv interface pointer for the current thread will be placed.

args: a pointer to a JavaVMAttachArgs structure.

RETURNS

Returns JNI_OK on success; returns a suitable JNI error code (a negative number) on failure.

EXCEPTIONS

None.

SINCE:

JDK/JRE 1.4

DetachCurrentThread

jint DetachCurrentThread(JavaVM *vm);

Detaches the current thread from a Java VM. All Java monitors held by this thread are released. All Java threads waiting for this thread to die are notified.

從Java VM中分離當前線程。 釋放該線程擁有的所有Java監視器。 所有等待該線程死亡的Java線程都會被通知。

As of JDK/JRE 1.2 , the main thread can be detached from the VM.
從JDK / JRE 1.2開始,可以從VM分離主線程。

LINKAGE:

Index 5 in the JavaVM interface function table.

PARAMETERS:

vm: the VM from which the current thread will be detached.

RETURNS:

Returns JNI_OK on success; returns a suitable JNI error code (a negative number) on failure.

GetEnv

jint GetEnv(JavaVM *vm, void **env, jint version);

LINKAGE:

Index 6 in the JavaVM interface function table.

PARAMETERS:

vm: The virtual machine instance from which the interface will be retrieved.
env: pointer to the location where the JNI interface pointer for the current thread will be placed.
version: The requested JNI version.

RETURNS:

If the current thread is not attached to the VM, sets *env to NULL, and returns JNI_EDETACHED. If the specified version is not supported, sets *env to NULL, and returns JNI_EVERSION. Otherwise, sets *env to the appropriate interface, and returns JNI_OK.

如果當前線程未連接到VM,則將* env設置爲NULL,並返回JNI_EDETACHED。 如果不支持指定的版本,請將* env設置爲NULL,並返回JNI_EVERSION。 否則,將* env設置爲適當的接口,並返回JNI_OK。

SINCE:

JDK/JRE 1.2

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章