JNI调用注意事项 及 JNI中的常用方法

3 篇文章 0 订阅
2 篇文章 0 订阅
所谓jni,就是java和c互相调用的方式。由于C语言调用java的比较少,所以,本文所指的就是用java调用C语言写的动态库的方式。 
用java调用C语言的动态库,可以在效率和安全性上获得一定的效果;但是由于C语言可以直接访问内存空间,如果在编码上不严谨,极容易出现小错误从而影响jdk/jre的正常运行。目前所见有以下几个问题: 
1. 内存泄漏;容易导致jdk/jre在运行期占用大量的内存,内存消耗会随着应用运行的时间逐步增加。 
2. 数组越界;会导致不可想象的后果,包括运算结果错误和jre dump。 
3. 读写空指针;直接就会导致jre dump。 
4. 接口不匹配;在hotspot上表现为jre dump,并且没有任何有意义的提示信息。 
综上,可知jni是一种风险较高的编程方式,如果不是从安全和效率的角度考虑,应尽量避免使用。 

对于必须要使用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 监视线程退出同步块




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值