1. 内存泄漏;容易导致jdk/jre在运行期占用大量的内存,内存消耗会随着应用运行的时间逐步增加。综上,可知jni是一种风险较高的编程方式,如果不是从安全和效率的角度考虑,应尽量避免使用。
2. 数组越界;会导致不可想象的后果,包括运算结果错误和jre dump。
3. 读写空指针;直接就会导致jre dump。
4. 接口不匹配;在hotspot上表现为jre dump,并且没有任何有意义的提示信息。
对于必须要使用jni的应用,应反复审查C部分的代码,注意以下几个方面:
1. 安排专人负责jni尤其是动态库部分的编码,并安排经验丰富的人员进行代码检查。
2. 注意保证java部分和C部分的接口保持一致,避免误提示信息的jre dump。
3. 在C程序中对java传入的参数的进行严格检查,尤其是数组参数和字符串参数,要注意数据的长度和合法性。
4. 在C程序中要注意字符串和字符数组的区别。对于java中String类的参数,在C语言中表现为字符串,以0x00为结束符,可以使用str*类函数操 作,譬如strcpy等;特别要注意用Get*String*类jdk提供的函数处理时可能是与语言编码息息相关的,譬如对于中文字符串GetStringLength得 到的长度与strlen是不一样的。而对于java中的byte[]类参数,在C语言中表现为字符数组,无结束符,需要自行获取数据长度,可以用mem*类 函数操作,譬如memcpy;要注意这类参数不能通过strlen得到准确长度,应自行传递数据长度或使用Get*ArrayLength类函数取得数据长度。
5. 要避免隐式的内存泄露,在C语言中注意如果有申请内存一定要释放,即*alloc和free要成对出现;而从java传递的参数中获取信息后也要及时 释放引用,即Get*和Release*类函数要成对使用,譬如在调用GetByteArrayElements后,应调用ReleaseByteArrayElements通知jre释放对这 部分内存的引用。
6. 要避免在C语言中出现读写空指针的情况,在对指针进行读写前应判断其可用性,C动态库的dump会导致jre的dump,由于jre中不存在 process的概念,这会使得整个jre退出。7. 防止数组读写越界,在C语言中出现读写越界时,可能会导致动态库dump,从而使得jre退出;但在某些系统/编译器下,可能会出现把数据写 到静态变量(static)区的情况,这时,不会出现dump的情况,但由于静态变量被修改,任何引用了静态变量的计算都会得到错误的结果;所 以,请尽量少用静态变量,如有使用,请注意保证变量的值不会被无意篡改。
1、 用来获取数组元素的JNI函数集
GetBooleanArrayElements,
GetByteArrayElements,
GetCharArrayElements,
GetShortArrayElements,
GetIntArrayElements,
GetLongArrayElements,
GetFloatArrayElements,
GetDoubleArrayElements;
2、 用来释放数组数据的函数集
ReleaseBooleanArrayElements,
ReleaseByteArrayElements,
ReleaseCharArrayElements,
ReleaseShortArrayElements,
ReleaseIntArrayElements,
ReleaseLongArrayElements,
ReleaseFloatArrayElements,
ReleaseDoubleArrayElements;
JNI中的主要方法
1、 用来处理字符串对象的函数组合
GetStringChars 获取字符串中的字符
GetStringLength 获取字符串的长度
GetStringUTFChars 获取字符串中得UTF字符
GetStringUTFLength 获取字符串UTF字符长度
NewString 创建新的字符串
NewStringUTF 创建新的UTF字符串
ReleaseStringChars 释放字符串字符
ReleaseStringUTFChars 释放字符串UTF字符
2、 用来处理数组对象的函数集合
GetArrayLength 获取数组的长度
Get<type>ArrayElements 获取相应类型的数组元素
Release<type>ArrayElements 释放相应类型的数组元素
Get<type>ArrayRegion 获取相应类型的数组的区域元素
Set<type>ArrayRegion 设置相应类型的数组的区域元素
GetObjectArrayElement 获取对象类型的数组元素
SetObjectArrayElement 设置对象类型的数组元素
3、 用来处理方法的函数集合
GetObjectClass 获取对象类
GetMethodID 获取方法ID
GetStaticMethodID 获取静态方法ID
Call<type>Method 调用返回值为<type>型的方法
CallStatic<returntype>Method 调用相应返回值类型的静态方法
4、 用来处理成员变量的函数集合
GetFieldID 获取数据域标志
GetStaticFieldID 获取静态数据域标志
Get<type>Field 获取<type>数据域
Set<type>Field 设置相应类型的数据域
GetStatic<type>Field 获取相应类型的静态数据域
SetStatic<type>Field 设置相应类型的静态数据域
5、 用来处理异常的函数集合
ExceptionClear 异常清除
ExceptionDescribe 输出异常调试信息
ExceptionOccurred 捕获异常
6、 用来处理引用的函数集合
NewGlobalRef 创建一个全局引用
DeleteGlobalRef 删除一个全局引用
DeleteLocalRef 删除一个局部引用
7、 用来处理线程同步的函数集合
MonitorEnter 监视线程进入同步块
MonitorExit 监视线程退出同步块