您的位置:首页 > 移动开发 > Android开发

【Android JNI】JNIEnv和JavaVM的区别

2014-10-15 21:30 190 查看
JNI的实现可涉及两个关键类:JNIEnv和JavaVM。

JavaVM:这个代表java的虚拟机。所有的工作都是从获取虚拟机的接口开始的。

第一种方式,在加载动态链接库的时候,JVM会调用JNI_OnLoad(JavaVM*
jvm, void* reserved)(如果定义了该函数)。第一个参数会传入JavaVM指针。
第二种方式,在native code中调用JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args)可以得到JavaVM指针。
两种情况下,都可以用全局变量,比如JavaVM*
g_jvm来保存获得的指针以便在任意上下文中使用。
Android系统是利用第二种方式Invocation interface来创建JVM的。

JNIEnv:JNI Interface Pointer, 是提供JNI Native函数的基础环境,线程相关,不同线程的JNIEnv相互独立。

JNIEnv只在当前线程中有效。本地方法不 能将JNIEnv从一个线程传递到另一个线程中。相同的 Java 线程中对本地方法多次调用时,传递给该本地方法的JNIEnv是相同的。但是,一个本地方法可被不同的 Java 线程所调用,因此可以接受不同的 JNIEnv。

JavaVM则可以在进程中的各线程间共享。理论上一个进程可以有多个JavaVM,但Android只允许一个(JavaVm and JIEnv)。需要强调的是JNIEnv是跟线程相关的。sdk文档中强调了do
not cache JNIEnv*,要用的时候在不同线程中再通过JavaVM *jvm的方法来获取与当前线程相关的JNIEnv*。两者都可以理解为函数表(Function Pointer Table), 前者是使用Java程序创建的运行环境(从属于一个JVM)提供JNI Native函数。

Java和Android中JavaVM对象有区别

在java里,每一个process可以产生多个java
vm对象,但是在android上,每一个process只有一个Dalvik虚拟机对象,也就是在android进程中是通过有且只有一个虚拟器对象来服务所有java和c/c++代码。

Java 的dex字节码和c/c++的*.so同时运行Dalvik虚拟机之内,共同使用一个进程空间。之所以可以相互调用,也是因为有Dalvik虚拟机。当java 代码需要c/c++代码时,在Dalvik虚拟机加载进*.so库时,会先调用JNI_Onload(),此时就会把JAVA
VM对象的指针存储于c层jni组件的全局环境中,在Java层调用C层的本地函数时,调用c本地函数的线程必然通过Dalvik虚拟机来调用c层的本地函数,此时,Dalvik虚拟机会为本地的C组件实例化一个JNIEnv指针,该指针指向Dalvik虚拟机的具体的函数列表,当JNI的c组件调用Java层的方法或者属性时,需要通过JNIEnv指针来进行调用。 当本地c/c++想获得当前线程所要使用的JNIEnv时,可以使用Dalvik虚拟机对象的JavaVM*
jvm->GetEnv()返回当前线程所在的JNIEnv*。

附 JNIEnv和JavaVM的定义。他们位于头文件jni.h。$NDK\platforms\android-5\arch-arm\usr\include\jni.h的部分代码

struct _JNIEnv;

struct _JavaVM;

#if defined(__cplusplus)

typedef _JNIEnv JNIEnv; //C++使用这个类型

typedef _JavaVM JavaVM; //C++使用这个类型

#else

typedef const struct JNINativeInterface* JNIEnv; //C使用这个类型

typedef const struct JNIInvokeInterface* JavaVM; //C使用这个类型

#endif

struct JNINativeInterface

{

/****省略了的代码****/

jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);

/****省略了的代码****/

jobject (*GetStaticObjectField)(JNIEnv*, jclass, jfieldID);

/****省略了的代码****/

};

struct _JNIEnv
{
const struct JNINativeInterface* functions;
#if defined(__cplusplus)
/****省略了的代码****/
jmethodID GetMethodID(jclass clazz, const char* name, const char* sig)
{ return functions->GetMethodID(this, clazz, name, sig); }
/****省略了的代码****/
jobject GetStaticObjectField(jclass clazz, jfieldID fieldID)
{ return functions->GetStaticObjectField(this, clazz, fieldID); }
/****省略了的代码****/
#endif /*__cplusplus*/
};

struct JNIInvokeInterface
{
/****省略了的代码****/
jint (*GetEnv)(JavaVM*, void**, jint);
jint (*AttachCurrentThreadAsDaemon)(JavaVM*, JNIEnv**, void*);
};

struct _JavaVM
{
const struct JNIInvokeInterface* functions;
#if defined(__cplusplus)
/****省略了的代码****/
jint GetEnv(void** env, jint version)
{ return functions->GetEnv(this, env, version); }
jint AttachCurrentThreadAsDaemon(JNIEnv** p_env, void* thr_args)
{ return functions->AttachCurrentThreadAsDaemon(this, p_env, thr_args); }
#endif /*__cplusplus*/
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: