【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*/
};
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*/
};
相关文章推荐
- 【Android JNI】JNIEnv和JavaVM的区别
- Android JNI开发(1)--JavaVM和 JNIEnv 动态注册本地方法
- Android之jni编译出现no matching function for call to '_JNIEnv::GetJava(JNIEnv* &, Java VM**)'解决办法)'
- Android底层JNI中的JavaVM和JNIEnv对象
- JNIEnv和Dalvik的JavaVM的关系
- JNI完全指南(十)——JavaVM与JNIEnv
- Android底层JNI中的JavaVM和JNIEnv对象
- JavaVM和JNIEnv
- JavaVM & JNIEnv
- Android JNI开发高级篇有关Android JNI开发中比较强大和有用的功能就是从JNI层创建、构造Java的类或执行Java层的方法获取属性等操作。 一、类的相关操作 1. jclass FindClass(JNIEnv *env, const char *name);
- 在Ubuntu为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口
- Android问题集锦转载之三:Javah 常见错误记录-NDK与JNI除错
- JAVA和Android的JNI的使用
- 在Ubuntu为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口
- 关于JAVA和Android的JNI的使用
- 在Ubuntu为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口
- Android JNI(JNI(JAVA同C++配合使用)
- Java JNI编程之 JNIEnv设计哲学
- Android中JNI的使用之一:Java原生JNI的使用、javah指令的使用以及图解教材
- C++程序员进军Android系列:C++跟JAVA的区别总结