文档章节

使用 JNI 时容易出错的地方相关总结

zhangyujsj
 zhangyujsj
发布于 2015/08/23 20:33
字数 1369
阅读 6
收藏 0
点赞 0
评论 0

把 jclass 和 jobject 弄混
一开始使用 JNI 时,很容易把对象引用(jobject 类型的值)和类引用(jclass 类型的值)弄混。
对象引用对应的是数组或者 java.lang.Object 及其子类的对象实例,而类引用对应的是java.lang.Class 的实例。
像 GetFieldID 这样需要传入 jclass 作为参数的方法做的是一个类操作,因为它是从一个类中获取字段的描述。
而 GetIntField 这样需要传入 jobject 作为参数的方法做的是一个对象操作,因为它从一个对象实例中获取字段的值。

 

混淆 ID 和引用
本地代码中使用引用来访问 JAVA 对象,使用 ID 来访问方法和字段。
引用指向的是可以由本地代码来管理的 JVM 中的资源。比如 DeleteLocalRef 这个本地函数,允许本地代码删除一个局部引用。
而字段和方法的ID由JVM来管理,只有它所属的类被 unload时,才会失效。
本地代码不能显式在删掉一个字段或者方法的 ID。
本地代码可以创建多个引用并让它们指向相同的对象。比如,一个全局引用和一个局部引用可能指向相同的对象。
而字段 ID 和方法 ID 是唯一的。
比如类 A定义了一个方法 f,而类 B从类 A中继承了方法 f,那么下面的调用结果是相同的:
jmethodID MID_A_f = (*env)->GetMethodID(env, A, "f", "()V");
jmethodID MID_B_f = (*env)->GetMethodID(env, B, "f", "()V");

 

访问权限失效
在本地代码中,访问方法和变量时不受 JAVA 语言规定的限制。比如,可以修改 private 和 final修饰的字段。
并且,JNI 中可以访问和修改 heap 中任意位置的内存。这些都会造成意想不到的结果。
比如,本地代码中不应该修改 java.lang.String 和 java.lang.Integer 这样的不可变对象的内容。否则,会破坏 JAVA 规范。

 

忽视国际化
JVM 中的字符串是 Unicode 字符序列,而本地字符串采用的是本地化的编码。实际编码的时候,
我们经常需要使用像 JNU_NewStringNative 和 JNU_GetStringNativeChars 这样的工具函数来
把 Unicode 编码的 jstring 转化成本地字符串,要对消息和文件名尤其关注,它们经常是需要国际化的,可能包含各种字符。
如果一个本地方法得到了一个文件名,必须把它转化成本地字符串之后才能传递给 C 库函数使用:

复制代码

JNIEXPORT jint JNICALL ava_MyFile_open(JNIEnv *env, jobject self, jstring name, jint mode) 
 { 
     jint result; 
     char *cname = JNU_GetStringNativeChars(env, name); 
     if (cname == NULL) { 
         return 0; 
     } 
     result = open(cname, mode); 
     free(cname); 
     return result; 
 }

复制代码

上例中,我们使用 JNU_GetStringNativeChars 把Unicode字符串转化成本地字符串。

 

jboolean 会面临数据截取的问题 
Jboolean是一个8-bit unsigned的C类型,可以存储0~255的值。其中,0对应常量JNI_FALSE,
而 1~255 对应常量 JNI_TRUE。但是,32 或者 16 位的值,如果最低的 8 位是 0 的话,就会引
起问题。
假设你定义了一个函数 print,需要传入一个 jboolean 类型的 condition 作为参数:
void print(jboolean condition)
 {
   /* C compilers generate code that truncates condition
       to its lower 8 bits. */
     if (condition) {
         printf("true\n");
     } else {
         printf("false\n");
     }
 }
 对上面这段代码来说,下面这样用就会出现问题:
int n = 256; /* the value 0x100, whose lower 8 bits are all 0 */
 print(n);
我们传入了一个非 0 的值 256(0X100),因为这个值的低 8 位(即,0)被截出来使用,上面
的代码会打印“false”。
根据经验,这里有一个常用的解决方案:
n = 256;
print (n ? JNI_TRUE : JNI_FALSE);

 

跨进程使用 JNIEnv
JNIEnv 这个指针只能在当前线程中使用,不要在其它线程中使用。

 

传递数据
像 int、char 等这样的基本数据类型,在本地代码和 JVM 之间进行复制传递,而对象是引用传递的。
每一个引用都包含一个指向 JVM 中相应的对象的指针,但本地代码不能直接使用这个指针,必须通过引用来间接使用。
比起传递直接指针来说,传递引用可以让 VM 更灵活地管理对象。
比如,你在本地代码中抓着一个引用的时候,VM那小子可能这个时候正偷偷摸摸地把这个引用间接指向的那个对象从一块儿内存区域给挪到另一块儿。
不过,有一点儿你放心,VM 是不敢动对象里面的内容的,因为引用的有效性它要负责。
瞅一下下图,你就会得道了。

 

这里有一些经验性的注意事项:
1、 尽量让 JAVA 和 C 之间的接口简单化,C 和 JAVA 间的调用过于复杂的话,会使得 BUG 调试、代码维护和 JVM 对代码进行优化都会变得很难。比如虚拟机很容易对一些 JAVA 方法进行内联,但对本地方法却无能为力。
2、 尽量少写本地代码。因为本地代码即不安全又是不可移植的,而且本地代码中的错误检查很麻烦。
3、 让本地代码尽量独立。也就是说,实际使用的时候,尽量让所有的本地方法都在同一个包甚至同一个类中。


本文转载自:http://www.cnblogs.com/lijunamneg/archive/2012/12/22/2829132.html

共有 人打赏支持
zhangyujsj
粉丝 23
博文 288
码字总数 224241
作品 0
广州
JNI/NDK基础开发

一、JNI/NDK介绍 什么是NDK? NDK全称是Native Development Kit,NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。 NDK集成了交叉编译器(...

AFinalDream ⋅ 2017/10/11 ⋅ 0

Mario_Q/jnitool

@jnitool version 1.0 工具的需求 这是一个代码生成工具是为了方便,自定义的Java结构体转成C++结构体方便C++的调用,通过对JNI的封装了方便C++和Java结构体之间的交互. 对自定义java结构体访...

Mario_Q ⋅ 2014/12/12 ⋅ 0

Java 使用 Tess4J 进行 图片文字识别 笔记

最近的工作中需要使用到从图片中识别文字的操作,就在网上找到到Tess4j.那么,现在来总结一下使用中遇到的问题. 关于Tess4J简价: http://tess4j.sourceforge.net/ (需要翻墙) 很简洁的项目主页...

周翔 ⋅ 2013/09/16 ⋅ 8

android源码-深入理解JNI技术

9/5/2016 2:10:30 PM android源码-深入理解JNI技术 本章涉及的源代码文件名及位置 AndroidRunTime.cpp (framework/base/core/jni/AndroidRunTime.cpp)JNIHelp.c (libnativehelper/JNIHelp.c)......

小米墨客 ⋅ 2016/09/07 ⋅ 3

Subeclipse验证失败的问题-已解决

最近Mac下面重新布置了一下开发环境,遇到一些问题,顺便记录一下。 PS:慢慢养成随手写博客的习惯吧,以便日后查看,话说这次重装MyEclipse之后,连怎么破解都没有思路了,搜了半天,原来破...

liongmagezi ⋅ 2013/09/30 ⋅ 0

深入理解JNI

深入理解JNI 本章主要内容 · 通过一个实例,介绍JNI技术和在使用中应注意的问题。 本章涉及的源代码文件名及位置 下面是本章分析的源码文件名及其位置。 · MediaScanner.java framework/ba...

xiaole0313 ⋅ 2016/03/31 ⋅ 0

JNI调用机制

JNI的简单介绍 Java Native Interface (JNI)是java本地调用接口,所谓的native就是调用c/c++的程序。 java调用C语言的情况一般有三种: 调用驱动。由于操作系统提供的驱动一般都是C接口,J...

henry-zhang ⋅ 2015/05/27 ⋅ 0

[深入理解Android卷一 全文-第二章]深入理解JNI

由于《深入理解Android 卷一》和《深入理解Android卷二》不再出版,而知识的传播不应该因为纸质媒介的问题而中断,所以我将在OSC博客中全文转发这两本书的全部内容。 第2章 深入理解JNI 本章...

邓凡平 ⋅ 2015/08/02 ⋅ 0

简单介绍Java和C/C++交互

1、Java调用C/C++: Java代码 [JNITest.java]: package darcy; public class JNITest { static{ System.loadLibrary("Hello"); } public native void HelloKitty(); public static void main(......

叶大侠 ⋅ 2014/03/18 ⋅ 0

从外部编码的角度再议Java乱码问题

从外部编码的角度再议Java乱码问题 石 琎 2017 年 12 月 07 日发布 在实际项目中,由于系统的复杂性,乱码的根源往往不容易快速定位,乱码问题不见得一定能通过在 Java 内部编解码的方式解决...

石 琎 ⋅ 2017/12/07 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

关于“幂等”操作

一个幂等(idempotent)操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同. 开发中, 我们经常考虑幂等操作的场景有“接口调用”、“MQ消费”、“自动任务”等 接口调用, 可能出现...

零二一七 ⋅ 17分钟前 ⋅ 0

Dubbo服务服务暴露之ProxyFactory Invoker

Dubbo服务暴露过程中有涉及到调用ProxyFactory 中方法获取Invoker对象的过程,现在我们来深究下源码,来看下这个过程是在做些什么,返回的Invoker 对象是什么,我们来看一下代码的切入点: ...

哲别0 ⋅ 32分钟前 ⋅ 0

GP两种连接方式性能测试

GP两种连接方式性能测试 Pivotal import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; public class GPQueryStrin......

仔仔1993 ⋅ 36分钟前 ⋅ 0

jsonrpc-4j代码解析

解析文件 AutoJsonRpcServiceImplExporter JsonServiceExporter AutoJsonRpcServiceImplExporter 路径:com.googlecode.jsonrpc4j.spring.AutoJsonRpcServiceImplExporter AutoJsonRpcServi......

郭恩洲_OSC博客 ⋅ 58分钟前 ⋅ 0

百度搜索

from selenium import webdriver import time brower=webdriver.Firefox() brower.get('http://www.baidu.com') input=brower.find_element_by_id('kw') input.send_keys('中南大学') time.s......

南桥北木 ⋅ 今天 ⋅ 0

tomcat 日志记录器

1、日志记录器是记录消息的组件 日志记录器需要与某个servlet 容器相关联 2、Logger 接口 共定义了5种日志级别:FATAL、ERROR、WARNING、INFORMATION、DEBUGGER setVerbosity 设置级别 setC...

职业搬砖20年 ⋅ 今天 ⋅ 0

Thrift RPC实战(三) Thrift序列化机制

1.Thrift基础架构 Thrift是一个客户端和服务端的架构体系,数据通过socket传输; 具有自己内部定义的传输协议规范(TProtocol)和传输数据标准(TTransports); 通过IDL脚本对传输数据的数据结构...

lemonLove ⋅ 今天 ⋅ 0

网站建设就要像2018世界杯的俄罗斯队大杀四方[图]

今天心情不错,因为昨天晚上观看了世界杯比赛,尤其是对俄罗斯队的大杀四方感到十分霸气侧漏啊,因此我联想到了自己的博客网站,我的博客是去年年底上线的,一直想建设一个关于读书和读后感作...

原创小博客 ⋅ 今天 ⋅ 0

linux 信号机制

signal(SIGPIPE, SIG_IGN); TCP是全双工的信道, 可以看作两条单工信道, TCP连接两端的两个端点各负责一条. 当对端调用close时, 虽然本意是关闭整个两条信道, 但本端只是收到FIN包. 按照TCP协...

xxdd ⋅ 今天 ⋅ 0

my.cnf, my-small.cnf, my-medium.cnf, my-large.cnf

1. my-small.cnf # Example MySQL config file for small systems.## This is for a system with little memory (<= 64M) where MySQL is only used# from time to time and it's importa......

周云台 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部