JNI总结(一)

JNI 是 Java平台中的一个强大特性。应用程序可以通过
JNI把 C/C++代码集成进 Java程序中。通过
JNI,开发者在利用 Java平台强大功能的同时,又不必放弃对原有代码的投资;因为
JNI是 Java平台定义的规范接口,当程序员向
Java代码集成本地库时,只要在一个平台中解决了语言互操作问题,就可以把该解决方案比较容易的移植到其他 Java平台中。

比如为 Dalvik添加了一个本地库,也可以把这个本地库很容易的移植到
J2SE和 Apache Harmony中,因为在
Java与 C/C++互操作方面,大家都遵循一套 API接口,即
JNI。

Java 平台(Java Platform)的组成:Java
VM和 Java API. Java应用程序使用 Java
语言开发,然后编译成与平台无关的字节码(.class文件)。
Java API由一组预定义的类组成。任何组织实现的 Java平台都要支持:Java
编程语言,虚拟机,和 API(译者:Sun对
Java 语言、虚拟机和 API有明确规范)。

平台环境:操作系统,一组本机库,和
CPU指令集。本地应用程序,
通常依赖于一个特定的平台环境,用
C、C++等语言开发,并被编译成平台相关的二进制指令,目标二进制代码在不同
OS 间一般不具有可移植性。Java平台(Java VM
和 Java API)一般在某个平台下开发。比如,Sun的
Java Runtime Environment(JRE)支持类 Unix和
Windows 平台. Java
平台做的所有努力,都为了使程序更具可移植性。

当 Java
平台部署到本地系统中,有必要做到让 Java 程序与本地代码协同工作。部分是由于遗留代码(保护原有的投资)的问题(一些效率敏感的代码用 C 实现,但现在 JavaVM 的执行效率完全可信赖),工程师们很早就开始以 C/C++为基础构建 Java 应用,所以,C/C++代码将长时间的与 Java 应用共存。

JNI让你在利用强大 Java
平台的同时,使你仍然可以用其他语言写程序。作为 JavaVM 的一部分,JNI 是一套双向的接口,允许 Java 与本地代码间的互操作。作为双向接口,JNI 支持两种类型本地代码:本地库和本地应用。用本地代码实现 Java 中定义的 native method 接口,使 Java 调用本地代码通过 JNI 你可以把 Java VM 嵌到一个应用程序中,此时 Java 平台作为应用程序的增强,使其可以调用 Java 类库比如,在浏览器中运行 Applet, 当浏览器遇到"Applet"标签,浏览器就会把标签中的内容交给
Java VM 解释执行,这个实现,就是典型的把 JavaVM 嵌入 Browser 中。JNI 不只是一套接口,还是一套使用规则。 Java 语言有"native"关键字,声明哪些方法是用本地代码实现的. 翻译的时候,对于"native method",根据上下文意思做了不同处理,当native method 指代 Java 中用"native"关键字修饰的那些方法时,不翻译;而当代码用C/C++实现的部分翻译成了本地代码。

上述,在应用中嵌入 Java VM的方法,是用最少的力量,为应用做最强扩展的不二选择,这时你的应用程序可以自由使用 Java API 的所有功能;大家有兴趣可以读一读浏览器是怎么扩展 Applet 的,或者读一读
Palm WebOS 的东西。

我们整个小组做了两个平台的扩展,设计、编码、测试和 debug 用了近一年半时间,代码量在 14000 行左右,做完扩展后,平台功能空前增强。我感觉做软件,难得不在编码,难在开始的设计和后期的测试、调试和优化,并最终商用,这就要求最终产品是一个强大而稳定的平台,达到此目标是个旷日持久的事. 看看 Java,Windows,Linux,Qt,WebKit 发展了多少年?向所有软件工程师致敬!

请记住,当 Java
程序集成了本地代码,它将丢掉 Java 的一些好处。

首先,脱离 Java
后,可移植性问题你要自己解决,且需重新在其他平台编译链接本地库。

第二,要小心处理 JNI
编程中各方面问题和来自 C/C++语言本身的细节性问题,处理不当,应用将崩溃。

一般性原则:做好应用程序架构,使 native methods定义在尽可能少的几个类里。

学习 JNI编程是个漫长的实践过程,会碰到无数问题。

用 C/C++编程,常见问题有内存泄露,指针越界...,此外使用了 JNI,还要面对JavaVM的问题:

?在本地代码中 new
一个 Java 对象后期望在本地代码中维护此对象的引用,如何避免被 GC;

? Java 面向对象语言的封装性被破坏了,Java 类中任何方法和属性对 JNI 都是可见的;不管它是 public 的,还是 private/protected/package 的

? 对LocalRef/GlobalRef 管理不善,会引发 Table Overflow Exception,导致应用崩溃

?从 JNI
调用 Java 的过程不是很直观,往往几行 Java 代码能搞定的事情,用 JNI 实现却要几百行

当你准备在项目中使用 JNI之前,请先考虑一下是否有其他更合适的方案。上节有关 JNI缺点的介绍,应该引起你足够的重视。这里介绍几个不通过 JNI 与其他语言交互的技术:

IPC 或者通过TCP/IP 网络方案 ( Android ASE)

数据库方面,可以使用 JDBC

使用 Java的分布式对象技术:Java IDL API  IPC 与 TCP/IP 是常用的基于协议的信息交换方案. 可以参考 Android 上的Binder 和ASE(Android Script Environment)。

一典型的解决方案是,Java程序与本地代码分别运行在不同的进程中. 采用进程分置最大的好处是:一个进程的崩溃,不会立即影响到另一个进程。但是,把Java 代码与本地代码置于一个进程有时是必要的。如下

Java API 可能不支某些平台相关的功能。比如,应用程序执行中要使用 Java API 不支持的文件类型,而如果使用跨进程操作方式,即繁琐又低效避免进程间低效的数据拷贝操作多进程的派生:耗时、耗资源(内存)用本地代码或汇编代码重写Java 中低效方法

总之,如果 Java
必须与驻留同进程的本地代码交互,请使用 JNI。写代码是技巧和艺术,看你想在设计上下多大功夫. 比如: Chrome,是多进程的典范,她的简洁、高效,令人叹服。关于 Java 应用程序如何与本地代码互操作的问题,在 Java 平台早期就被提了出来.JDK1.0 包括了一套与本地代码交互的接口。当时许多 Java 方法和库都依赖本地方法实现(如 java.io, java.net)。但是,JDK release 1.0 有两个主要问题:Java 虚拟机规范未定义对象布局,本地代码访问对象的成员是通过访问
C 结构的成员实现的本地代码可以得到对象在内存中的地址,所以,本地方法是 GC 相关的为解决上述问题对 JNI 做了重新设计,让这套接口在所有平台都容易得到支持。虚拟机实现者通过 JNI 支持大量的本地代码工具开发商不用处理不同种类的本地接口所有 JNI 开发者面对的是操作 JavaVM 的规范 APIJNI 的首次支持是在 JDK release 1.1,但 1.1 内部 Java 与本地代码的交互仍然使用原始方式(JDK 1.0). 但这种局面,没有持续很久,在 Java 2 SDK release1.2
中 Java 层与本地代码的交互部分用 JNI 重写了。

作为 JavaVM规范的一部分,Java 层与本地代码的交互,都应通过 JNI实现

时间: 2024-10-30 02:21:19

JNI总结(一)的相关文章

Delphi使用android的NDK是通过JNI接口,封装好了,不用自己写本地代码,直接调用

一.Android平台编程方式:      1.基于Android SDK进行开发的第三方应用都必须使用Java语言(Android的SDK基于Java实现)      2.自从ndk r5发布以后,已经允许完全用C/C++ 来开发应用或者游戏,而不再需要编写任何Java 的代码   Android程序运行在Dalvik虚拟机中,NDK允许用户使用类似C / C++之类的原生代码语言执行部分程序. 二.跨平台移动开发   Delphi使用android的NDK是通过JNI接口,封装好了,不用自己

[转]Ubuntu下使用Jni开发例子

http://www.cnblogs.com/zxglive2006/archive/2012/01/15/2323110.html 先用eclipse 创建 Java Project; 然后直接在项目中添加Prompt.java文件,放在default package下(最好不要添加包,否则容易出错). 1. 编写Java文件,在其中声明native方法, 并通过static 语句块加载动态链接库,示例Prompt.java代码如下: class Prompt { private native

Android中JNI调用时出现accessed stale local reference的问题

之前在做一个native的模块时遇到这样一个问题: 代码运行在android2.3上没有任何问题,可是在4.2上运行时报出了:JNI ERROR (app bug): accessed stale local reference 的错误. 后来在StackOverflow上找到了问题的答案.简单来说就是  4.0以上的android系统GC在垃圾回收时为了减少内存碎片,会对内存进行整理,整理时必然会移动对象的内存地址,这时C代码的指针还指向原来对象的地址,这时该对象已经被移动到了其他位置,因此会

JTI + JNI,为Java程序提供获取JVM内部信息的通道

首先,JTI是啥? HotSpot JVM是使用C++写的,在操作系统层面来看,java.exe进程与其他进程并无特别之处.任何一个进程都可以加载第三方的DLL,JTI就是java.exe开放出来的向Java.exe进程注入dll的接口.也就是说,开发者根据JTI定义好的规范,用C++写一个dll,这个dll就可以被java.exe进程加载了[启动jvm的时候要加上-agentlib参数]. JTI的详细资料参见以下网址:http://docs.oracle.com/javase/7/docs/

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/NDK开发指南(三)——JNI数据类型及与Java数据类型的映射关系

转载请注明出处:http://blog.csdn.net/xyang81/article/details/42047899 当我们在调用一个Java native方法的时候,方法中的参数是如何传递给C/C++本地函数中的呢?Java方法中的参数与C/C++函数中的参数,它们之间是怎么转换的呢?我猜你应该也有相关的疑虑吧,咱们先来看一个例子,还是以HelloWorld为例: HelloWorld.java: package com.study.jnilearn; class MyClass {}

android使用c通过jni回调java

很多场合都有这样的需求,由于以前都是java调用c的接口,没有做过回调,今天花了大半天时间把这个流程跑通了,记录一下,以备后用.这里发句牢骚,那些网上分享出来的代码,请问你们确实是能正常工作吗?还有查来查去都是那几份,大家转载精神可嘉啊 jni相关头文件代码 /* DO NOT EDIT THIS FILE - it is machine generated */ #include /* Header for class com_example_ndktest_CallbackTest */ #

jni ndk 入门

1. Linux环境模拟,下载sygwin 安装,选择devl 和shell -> install sygwin 中的配置ndk环境,进入安装目录c:/cygwin64 etc/profile文件配置ndk的环境 //37行 PATH="/usr/local/bin:/usr/bin:/cygdrive/d/android-ndk-r9d-windows-x86_64/android-ndk-r9d${PATH:+:${PATH}}" 2. 下载ndk 3. 开发,参考于ndk/

在 Linux 平台下使用 JNI

引言 Java 的出现给大家开发带来的极大的方便.但是,如果我们有大量原有的经过广泛测试的非 Java 代码,将它们全部用 Java 来重写,恐怕会带来巨大的工作量和长期的测试:如果我们的应用中需要访问到特定的设备,甚至是仅符合公司内部信息交互规范的设备,或某个特定的操作系统才有的特性,Java 就显得有些力不从心了.面对这些问题,Sun 公司在 JDK1.0 中就定义了 JNI 规范,它规定了 Java 应用程序对本地方法的调用规则. 实现步骤及相关函数使用 本文将一步步说明在 Linux 平

Java中JNI的使用详解第一篇:HelloWorld

今天开始研究JNI技术,首先还是老套路,输出一个HelloWorld:具体流程如下:在Java中定义一个方法,在C++中实现这个方法,在方法内部输出"Hello World",然后再回到Java中进行调用.分为以下步骤: 第一步:在Eclipse中建立一个类:JNIDemo 1 package com.jni.demo; 2 public class JNIDemo { 3 //定义一个本地方法 4 public native void sayHello(); 5 public sta