`
leongod
  • 浏览: 63717 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

JNIEnv的哲学

阅读更多

Java通过JNI 机制调用c/c++写的native程序。c/c++开发的native程序需要遵循一定的JNI规范,下面的例子就是一个JNI函数声明:

JNIEXPORT jint JNICALL Java_jnitest_MyTest_test
  (JNIEnv 
* env, jobject obj, jint arg0);

JVM负责从Java Stack转入C/C++ Native Stack。当Java进入JNI调用,除了函数本身的参数(arg0),会多出两个参数:JNIEnv指针和jobject指针。
JNIEnv指针是JVM创建的,用于Native的c/c++方法操纵Java执行栈中的数据,比如Java Class, Java Method等。

首先,JNI对于JNIEnv的使用, 提供了两种语法: c语法以及c++语法,如下:
c语法:

jsize len  =  ( * env) -> GetArrayLength(env,array);

c++语法:

jsize len  = env -> GetArrayLength(array);

(注:由于C语言并不支持对象的概念,所以C语法中需要把env作为第一个参数传入,类似于C++的隐式参数this指针).


另外: JNIEnv有几个设计的原则:
第一、JNIEnv指针被设计成了Thread Local Storage (TLS)变量,也就是说每一个Thread, JNIEnv变量都有独立的Copy。这样做的原因主要是考虑到:
由于JVM要运行在多个平台(除了主流的Windows,Linux等平台),JNI内部实现 很 多要依赖到TLS, 为了减少对TLS的依赖,所有TLS based的数据都会存放于JNIEnv中。这样相当于只依赖一个TLS based的变量JNIEnv。由于JNIEnv指针是TLS的,所以你不能把Thead#1使用的JNIEnv传给Thread#2使用。

第 二、JNIEnv中定义了一组函数指针,c/c++ Native程序是通过这些函数指针操纵Java数据。这样设计的好处是:你的c/c++ 程序不需要依赖任何函数库,或者DLL。由于JVM可能由不同的厂商实现,不同厂商有自己不同的JNI实现,如果要求这些厂商暴露约定好的一些头文件和 库,这不是灵活的设计。
而且使用函数指针表的另外一个好处是: JVM可以根据启动参数动态替换JNI实现。比如:类似于C库,JNI实现为了性能起见,并没有对调用者传入的参数进行检查。但是在调试阶段,也许这种检 查是很必要的,帮助你尽早发现BUG。例如如果你使用IBM JDK,你可以指定JVM参数–Xcheck:jni,告诉JVM使用带检查的JNI实现。

参考:
http://java.sun.com/docs/books/jni/html/jniTOC.html

分享到:
评论

相关推荐

    Android Studio JNI 的静动态注册开发以及CC++ JNIEnv的理解

    另外,由于每个Java线程有自己的JNIEnv,所以在多线程环境下,需要确保每个线程都有自己的JNIEnv实例。 总结,Android Studio中的JNI开发涉及到静动态注册、JNIEnv的使用,以及Java和C/C++之间的数据转换和交互。...

    Eclipse + vs2013 编写第一个JNI HelloWorld

    JNI(Java Native Interface)是Java平台的标准接口,它允许Java代码和其他语言写的代码进行交互。在本教程中,我们将利用Eclipse IDE和Microsoft Visual Studio 2013(VS2010)来创建一个简单的JNI示例,展示如何从...

    JNI_ENV_FUNCTIONS

    JNI_ENV_FUNCTIONS 函数及对应的编码,Android下ARM静态反编译逆向

    jni代码示例

    2. **错误的线程创建方式**:在C++代码中,如果通过原生的方式创建了新的线程并尝试调用JNI函数,而没有正确地将JNIEnv指针传递给新线程,就会出现这个错误。Java线程和JNI环境是紧密关联的,因此,新线程必须在启动...

    打造JNI_高焕堂_android_3.doc

    JNIEnv对象包含了指向VM函数表的指针,每个线程在首次进入VM调用本地函数时,都会获得一个对应的JNIEnv对象。由于每个线程有自己的JNIEnv对象,这提高了多线程的安全性,避免了数据共享时可能产生的冲突。 当需要在...

    android jni常用函数详解

    - **env**: 指针,指向JNIEnv结构体,用于访问JNI接口的方法。 - **jobject**: Java对象的句柄。 - **jstring**: Java字符串对象的句柄。 - **jclass**: Java类的句柄。 - **jmethodID**: Java方法标识符。 - **...

    dalvik虚拟机运行过程分析

    1. **JNIEnv.CallStaticVoidMethod**:在C++层,JNIEnv是一个结构体,它包含了一个指向`JNINativeInterface`的指针。这个接口定义了一系列的函数,用于与Java层进行交互。`CallStaticVoidMethod`是JNIEnv中的一个...

    JNI层创建的线程中回调java方法

    1. **使用JNIEnv**:JNIEnv是一个指向一系列函数指针的结构体,它提供了在本地代码中调用Java方法的接口。当JNI函数被Java方法调用时,JNIEnv会被自动传入。但是,如果在本地线程中,JNIEnv不会自动设置,所以我们...

    JNI层中创建的线程中回调java方法代码

    因此,我们需要将`JNIEnv`指针保存在全局变量或结构体中,并在新线程中通过JNI的`AttachCurrentThread()`方法获取有效的`JNIEnv`实例。 ```c++ void* callbackThreadFunc(void* arg) { JNIEnv* env = (JNIEnv*) ...

    C#调用JAVA方法

    4. **调用Java方法**:使用`JNIEnv.CallObjectMethod`、`JNIEnv.CallVoidMethod`等方法,根据返回值类型和参数类型选择合适的方法。 5. **处理结果**:将Java对象的结果转换回.NET对象,以便在C#中进一步处理。 **...

    如何在android的jni线程中实现回调

    由于JNI环境 (`JNIEnv* env`) 是与线程绑定的,所以不能直接在JNI线程中使用Java方法ID。需要使用`JavaVM*`接口来获取新的`JNIEnv`实例。首先,保存`JavaVM`指针,在JNI初始化时通过`AttachCurrentThread()`或`...

    Android Java代码与JNI交互 JNI访问Java类方法 (七)

    - 对于静态方法,使用`jmethodID GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig)`。 - 对于实例方法,使用`jmethodIDGetMethodID(JNIEnv *env, jclass clazz, const char *...

    JIN基本使用二工程资源

    这通常通过调用`RegisterNatives`函数实现,该函数接收`JNIEnv`指针、Java类的全局引用以及一个描述本地方法的数组。这样,我们可以在运行时根据需要注册不同的本地方法,增强了程序的可扩展性。 2. **在JNI线程中...

    SourceInsight属性设置

    SourceInsight编辑器常用属性设置,一款常用编辑器

    jni.h 头文件

    1. **JNIEnv指针**:JNIEnv是一个指向结构体的指针,包含了各种用于执行Java方法、访问对象和数组的函数指针。在本地方法中,JNIEnv是第一个传递的参数,它提供了与Java虚拟机(JVM)的接口。 2. **本地方法签名**...

    轻松学会JNI层多线程回调java方法

    Java中的`JNIEnv*`指针是线程相关的,因此在多线程环境中,不能直接在新线程中使用它。为了解决这个问题,我们需要在新线程中创建一个新的JNI环境,并使用`AttachCurrentThread()`或`AttachCurrentThreadAsDaemon()`...

    Xamarin.Android 引用so

    `JNIEnv* env`和`jobject thiz`分别代表JNI环境指针和Java对象的引用。 在Java层,对应的JNI方法会像下面这样声明: ```java public native String stringFromJNI(); ``` 当C#调用`stringFromJNI`时,会映射到...

Global site tag (gtag.js) - Google Analytics