jni 基础

1.
java层对应到JNI层
除了 基本类型,基本类型数组,string,throwable,class 之外,都是用jobject来代替

2.
JNIEnv是native层,一个线程作用域的,调用虚拟机方法的对象
一个线程只能用自己的JNIEnv对象(类似Threadlocal的作用于效果,和线程对象相关),如果没有
那么通过JavaVM的AttachCurrentThread 获得当前线程的JNIEnv
当当前线程结束时,调用JavaVM->DetachCurrentThread 释放对应的资源

3.
使用java对象,首先要定位到对象的jfieldID 或 jmethodID
这样可以读写/访问 对象的成员变量或成员函数

一般先用FindClass找到jclass
然后用GetMethodID(jclass,methodName,methodSig)得到jmethodID
然后用env->CallXXXXMethod(jobject,jmethodID,params...)
XXXX为返回值类型的名称

成员变量访问是类似的
SetXXXXField
GetXXXXField

XXXX是成员变量类型名称
如Object,Byte,Int。。。。

4.
jstring

env->
NewString new一个jstring对象(存储Unicode)
NewStringUTF new一个jstring对象(存储Unicode,并用UTF-8编码)

const jchar* GetStringChars(jstring string, jboolean* isCopy)
const char* GetStringUTFChars(jstring string, jboolean* isCopy) 得到一个 UTF编码的jstring的 char数组

typedef uint16_t jchar; /* unsigned 16 bits */

当在Native层通过GetStringXXXChars获取到了char* ,并使用完成后,需要手动调用ReleaseStringChars() 或 ReleaseStringUTFChars()
释放jstring对象,否则可能造成在native层导致JVM产生内存泄露

5.
函数签名
签名格式,和类型映射名称
格式:(参数类型1;参数类型2;参数类型3;。。。。;)返回值类型

类型:
基本类型,对象,int数组,对象数组
这4类

基本类型: 有一对一的类型名称映射
对象为: L/对象包名/对象名;
int数组为: [I
对象数组为: [L/对象包名/对象名;

例如 int add(float, float) 的签名为
(F;F;)I

=====

垃圾回收

java层传递的一些对象,如 thiz 可能在运行中会被垃圾回收。
所以如果需要在native层保存这个引用,需要小心在下次使用的时候,判断一下是否被回收了
native层的引用,不像java层,被虚拟机管理了强引用等方式来进行垃圾回收,也就是说
这里引用了一个地址,jvm并不知道

那么jni有3种为我们提供的引用策略,我们产生了一个引用,并且根据引用方式不同,jvm对这些引用的回收策略也不同

1.LocalRefernce 本地引用。作为函数参数传递进来,离开native函数后,这些参数可能被回收
2.GlobalRefrence 全局引用。如果不主动释放,就不会被垃圾回收。(类似java层,从GCRoot可达的强引用)
3.WeakGlobalRefrence 全局弱音引用。在jvm运行过程种可能会被回收,调用前用JNIEnv的IsSameObject 判断某个引用是否被回收了(和java层的WeakRefrece有些类似)

2.GlobalRefrence:
如果需要将一个LocalRefernce转为GlobalRefrence
env->NewGlobalRef(ref)

往往在native对象的构造函数中这样使用
然后在析构函数中用
env->DeleteGolbalRef(ref) 解除引用

1.LocalRefernce:
虽然可以等函数调用完后,会自动回收java对象,但是也可以手动立即回收
调用
env->DeleteLocalRef(jref)
原因是,如果在这个函数里new了太多临时的java对象,而不即时手动清除,可能在函数执行过程中会产生内存溢出

====

JNI中的异常

在jni中如果调用某个jnienv的函数产生了异常,
那么不会立刻中断本地函数的执行,
要等到当前函数执行完后,返回到java层后,才会抛出异常
如果在native层产生了不可恢复的异常(业务逻辑层面上的)
那么需要做一些手动的资源清除,如释放全局变量,然后等
回到java层再catch异常

jni层可以获取,修改产生的异常
ExceptionOccured 是否有异常发生
ExceptionClear 清理掉发生的异常信息
ThrowNew 向java层抛出异常

====

原文地址:https://www.cnblogs.com/cyy12/p/12154326.html

时间: 2024-10-17 08:38:30

jni 基础的相关文章

Android JNI(一)——NDK与JNI基础

本系列文章如下: Android JNI(一)——NDK与JNI基础 Android JNI学习(二)——实战JNI之“hello world” Android JNI学习(三)——Java与Native相互调用 Android JNI学习(四)——JNI的常用方法的中文API Android JNI学习(五)——Demo演示 本片文章大纲如下: 1.导读 2.什么是NDK 3.为什么使用NDK 4.NDK到SO 5.JNI 大纲.png 一.导读 在Android OS上开发应用程序,Goog

【转】Android JNI编程—JNI基础

原文网址:http://www.jianshu.com/p/aba734d5b5cd 最近看到了很多关于热补的开源项目——Depoxed(阿里).AnFix(阿里).DynamicAPK(携程)等,它们都用到了JNI编程,并且JNI编程也贯穿了Android系统,学会JNI编程对于我们学习研究Android源码.Android安全以及Android安全加固等都是有所帮助的.但是对于我们这些写Android应用的,大部分时间都是在使用Java编程,很少使用C/C++编程,对于JNI编程也了解的比较

JNI基础学习

1.JNI(Java Native Interface): 它允许Java代码和其他语言写的代码进行交互,JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了.下图是java与c的交互表现: 2.JNI的编写与编译流程: 1)编写java文件,声名Native方法 2)javac编译java文件 3)javah -jni 编译生成Native方法的头文件 4)用c/c++实现Native方法 5)编译Native方法 6)在JVM运

JNI基础

1,JNI基本使用, (1)新建一个java类(com.example.jniparsedata.ParseData),专门用于和c进行交互 (2)在java类中声明方法 public native String StringHellowFromC(); (3)进入该类所在目录(../src),使用javah 指令,编译该类javah com.example.jniparsedata.ParseData,在Android工程中新建目录jni,将生成的com_example_jniparsedat

JNI基础知识

JNI是在学习Android HAL时必须要面临一个知识点,如果你不了解它的机制,不了解它的使用方式,你会被本地代码绕的晕头转向,JNI作为一个中间语言的翻译官在运行Java代码的Android中有着重要的意义,这儿的内容比较多,也是最基本的,如果想彻底了解JNI的机制,请查看: http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/design.html 本文结合了网友ljeagle写的JNI学习笔记和自己通过JNI的手册及Androi

Android JNI编程—JNI基础

什么是JNI,怎么使用 JNI--Java Native Interface,它是Java平台的一个特性(并不是Android系统特有的).其实主要是定义了一些JNI函数,让开发者可以通过调用这些函数实现Java代码调用C/C++的代码,C/C++的代码也可以调用Java的代码,这样就可以发挥各个语言的特点了.那么怎么使用JNI呢,一般情况下我们首先是将写好的C/C++代码编译成对应平台的动态库(windows一般是dll文件,linux一般是so文件等),这里我们是针对Android平台,所以

Android JNI基础篇

https://blog.csdn.net/quwei3930921/article/details/78820991 ①JNI是什么?Java Native Interface,它是java和C/C++相互通信的接口. ②JNI需要引入jni.h头文件 ③加载so库 System.loadLibrary(libname); ④android studio通过CMakeLists.txt文件配置需要生成的so库,通过cmake命令来生成so库; ⑤CMakeLists.txt配置详情 add_l

JNI基础 给c传递int数组,c对数组处理完毕返回给java

(1)获取java数组的长度 int length = (*env)->GetArrayLength(env,jarray); (2)得到数组的指针 int * arr = (*env)->GetIntArrayElements(env,jarray,0); (3)遍历数组中的每个元素,对其进行加5操作 int i = 0;    for(;i<length;i++)    {        (*(arr + i)) += 5;    } (4)返回数组 return jarray;

JNI基础 将字符串传递给c,在c中拼接后返回给java

(1)首先将java传递过来的字符串转化成c的char类型的数组,代码如下char*   Jstring2CStr(JNIEnv*   env,   jstring   jstr){    char*   rtn   =   NULL;    jclass   clsstring   =   (*env)->FindClass(env,"java/lang/String");    jstring   strencode   =   (*env)->NewStringUTF