`
joanzq
  • 浏览: 71303 次
  • 性别: Icon_minigender_2
  • 来自: 武汉
社区版块
存档分类
最新评论

如何用JNI技术提高Java的性能详解

    博客分类:
  • Java
阅读更多

如何用JNI技术提高Java的性能详解

 

阻碍Java获得广泛应用的一个主要因素是Java程序的运行效率。Java是介于解释型和编译型之间的一种语言,同样的程序,如果用编译型语言C来实现,其运行速度一般要比Java快一倍以上。Java具有平台无关性,这使人们在开发企业级应用的时候总是把它作为主要候选方案之一,但是性能方面的因素又大大削弱了它的竞争力。为此,提高Java的性能就显得十分重要。  



 

 问题的提出

Sun公司及Java的支持者们为提高Java的运行速度已经做出了许多努力,其中大多数集中在程序设计的方法和模式选择方面。由于算法和设计模式的优化是通用的,对Java有效的优化算法和设计模式,对其他编译语言也基本同样适用,因此不能从根本上改变Java程序与编译型语言在执行效率方面的差异。

JIT(Just In Time,及时编译)技术是个比较好的思想。它的基本原理是:首先通过Java编译器把Java源代码编译成平台无关的二进制字节码。然后在Java程序真正执行之前,系统通过JIT编译器把Java的字节码编译为本地化机器码。最后,系统执行本地化机器码,节省了对字节码进行解释的时间。这样做的优点是大大提高了Java程序的性能,缩短了加载程序的时间;同时,由于编译的结果并不在程序运行间保存,因此也节约了存储空间。缺点是由于JIT编译器对所有的代码都想优化,因此同样也占用了很多时间。

动态优化技术是提高Java性能的另一个尝试。该技术试图通过把Java源程序直接编译成机器码,以充分利用Java动态编译和静态编译技术来提高Java的性能。该方法把输入的Java源码或字节码转换为经过高度优化的可执行代码和动态库 (Windows中的. dll文件或Unix中的. so文件)。该技术能大大提高程序的性能,但却破坏了Java的可移植性。

JNI技术

实际上,有一种通常为我们忽视的技术可以在很大程度上解决这个难题,那就是JNI(Java Native Interface, Java本地化方法)。主张采用纯Java的人们通常反对本地化代码的使用,他们认为在Java程序执行的过程中调用C/C++程序会影响程序的可移植性和安全性。还有一些人认为JNI只是对过去混合编程技术的简单扩展,其实际目的是为了充分利用大量原有的C程序库。

其实,我们不必拘泥于严格的平台独立性限制,因为采用JNI技术只是针对一些严重影响Java性能的代码段,该部分可能只占源程序的极少部分,所以几乎可以不考虑该部分代码在主流平台之间移植的工作量。同时,也不必过分担心类型匹配问题,我们完全可以控制代码不出现这种错误。此外,也不必担心安全控制问题,因为Java安全模型已扩展为允许非系统类加载和调用本地方法。根据Java规范,从JDK 1. 2开始,FindClass将设法找到与当前的本地方法关联的类加载器。如果平台相关代码属于一个系统类,则无需涉及任何类加载器; 否则,将调用适当的类加载器来加载和链接已命名的类。换句话说,如果在Java程序中直接调用C/C++语言产生的机器码,该部分代码的安全性就由Java虚拟机控制。

JNI实现步骤

编写JNI代码的大致流程如下图所示:

JNI实现流程图

1. 首先编写需要JNI功能的Java类源文件。其中,需要JNI实现的方法应当用native关键字声明。在该类中,用System. loadLibrary()方法加载需要的动态链接库。关键代码如下:

//Compute.java

……

public class Compute {

public native double comp (double [] params);

……

static {

// 调用动态链接库

System. loadLibrary(“mathlib”);

}

……

}

2. 将该类源文件用Java类编译器编译成二进制字节码文件。由于采用了native关键字声明,编译器会忽视没有代码体的JNI方法部分。

3. 利用javah -jni *.class 生成相关JNI方法的头文件。我们可以手工生成该文件,但是由于Java虚拟机是根据一定的命名规范完成对JNI方法的调用,所以手工编写头文件需要特别小心。

上述文件产生的头文件部分代码如下:

//Compute. h

……

extern “C” {

JNIEXPORT jdouble JNICALL Java_Compute_comp (JNIEnv *, jobject, jdoubleArray);

}

……

可以看出,JNI函数名称分为三部分:首先是Java关键字,供Java虚拟机识别;然后是调用者类名称(全限定的类名,其中用下划线代替名称分隔符);最后是对应的方法名称,各段名称之间用下划线分割。

JNI函数的参数也由三部分组成: 首先是JNIEnv *,是一个指向JNI运行环境的指针;第二个参数随本地方法是静态还是非静态而有所不同——非静态本地方法的第二个参数是对对象的引用,而静态本地方法的第二个参数是对其 Java 类的引用; 其余的参数对应通常 Java 方法的参数,参数类型需要根据一定规则进行映射。

4. 根据头文件编写相应方法的实现代码。由于篇幅所限,具体的实现部分在此不再赘述。在编码过程中,需要注意变量的长度问题,例如Java的整型变量长度为32位,而C语言为16位,所以要仔细核对变量类型映射表,防止在传值过程中出现问题。

5. 利用C/C++编译器将JNI实现代码编译成动态链接库。调用者类中需要显式调用该链接库。

在Win32环境下,可以利用Visual C ++或其他能产生DLL文件的C/C++编译器将实现代码编译成动态链接库。笔者利用的是Microsoft.NET Framework的编译器。编译指令如下,其中%Java_HOME%是笔者的jdk安装目录变量:

cl -I%Java_HOME%\include

-I%Java_HOME%\include\win32

-LD jnicomp. c -Femathlib. dll

在Sun Soloaris下,相应指令为:

cc -G -I/usr/local/java/include -I/usr/local/java/include/solaris jnicomp. c \

-o mathlib. so

注意,编译的时候需要用I指令包含必要的库文件路径。

经过上述处理,就基本上完成了一个包含本地化方法的Java类的开发。

JNI技术的应用

一些主要的Java技术,如JDBC和RMI,大部分都采用JNI方式实现。但是,采用JNI确实会影响程序的平台无关性,所以只能在特别需要的地方才能使用。通常来说,如果遇到下面的情况,我们可以考虑JNI:

● 需要直接操作物理设备,而没有相关的驱动程序,这时候我们可能需要用C甚至汇编语言来编写该设备的驱动,然后通过JNI调用;

● 涉及大量数学运算的部分,用Java会带来些效率上的损失;

● 用Java会产生系统难以支付的开销,如需要大量网络链接的场合;

● 存在大量可重用的C/C++代码,通过JNI可以减少开发工作量,避免重复开发。

另外,在利用JNI技术的时候要注意以下几点:

● 由于Java安全机制的限制,不要试图通过Jar文件的方式发布包含本地化方法的Applet到客户端;

● 注意内存管理问题,虽然在本地方法返回 Java 后将自动释放局部引用,但过多的局部引用将使虚拟机在执行本地方法时耗尽内存;

● JNI技术不仅可以让Java程序调用C/C++代码,也可以让C/C++代码调用Java代码。

分享到:
评论
2 楼 duronshi 2008-02-02  
不错,我也一直在用delphi编写dll,最后用java通过dll来控制硬件
多发点这样的资料
如果有需要的话,我可以帮大家写
1 楼 billy1977 2008-02-02  
JNI我曾经用过,只能调用一些相对简单的函数,如果这个函数里包含有复杂对象的创建就会有问题,服务器运行一段时间后会报堆栈溢出,然后服务器死掉,研究了很久也没有结果,可能是JVM的内存管理和JNI调用的本地dll的内存管理有冲突,而且系统里有几个dll,每次要设置Path路径也很烦,最后我放弃使用JNI了。

相关推荐

    [JAVA]使用JNI技术实现JAVA程序调用dll

    [JAVA]使用JNI技术实现JAVA程序调用dll、[JAVA]使用JNI技术实现JAVA程序调用dll

    Java本地调用JNI使用规范详解.doc

    本文档主要讲述的是Java本地调用JNI使用规范详解;JNI概述;JavaNative Interface的缩写,中文为Java本地调用。从Java1.1开始,JNI即成为Java标准的一部分。 JNI设计的目的是为了允许Java代码与其他语言进行交互。但...

    android JNI C 调用Java

    android JNI C 调用Java

    JNI技术各类文档

    jni详解 JNI设计实践之路 JNI技术手册 Java_JNI_编程进阶 android_jni操作指南

    JNI DEMO:java jni技术 调用 c/c++ 的dll

    java 调用 dll 的方法,即JNI的使用,demo中有get()/set()方法,操作步骤详细,即使是没用过java的程序员按照步骤依然可以成功。

    jni C调用java示例

    JNI中C代码调用java的小示例。android studio2.3.3开发

    JNI技术开发步骤详解

    JNI技术在嵌入式软件开发中应用学些笔记

    利用JNI实现Java调用C++库

    利用JNI技术实现Java中调用C++编写的函数库示例程序源码,并附上参考JNI文档。 详情见本人博客:Java学习之通过JNI调用C/C++编写的dll链接库(图文教程)(http://write.blog.csdn.net/postlist)

    java jni 传递结构体

    文档里描述了如何通过jni方法在java与c++代码之间传递非基本类型数据

    JNI中C层调用Java层函数

    这是一个简单的JNI开发中C层调用Java层函数的事例工程,对应的博客地址是:http://blog.csdn.net/hty1053240123/article/details/52126386

    JNI使用规范详解.pdf

    JNI,全称为Java Native Interface,即Java本地接口,JNI是Java调用Native 语言的一种特性。...同时,这个特性使我们可以复用以前用C/C++写的大量代码JNI是一种在Java虚拟机机制下的执行代码的标准机制。

    jni回调Java层函数示例

    NI是Java Native Interface的缩写,是Java平台的重要特性,使得Java代码可以方便地与C/C++代码...本文主要给出一份示例代码(工程文件见附件),描述如何在Android的JNI层开启一个线程,并在线程中回调Java层的函数。

    使用JNI进行JAVA和C++之间的互调

    在VS2013中使用JNI进行JAVA和C++之间的互调,这两个文件只是项目中的一部分,仅供参考

    Android 深入研究JNI详解

    此时,VM扮演着桥梁的角色,让Java与C组件能通过标准的JNI介面而相互沟通。 应用层的Java类是在虚拟机(VM: Vitual Machine)上执行的,而C件不是在VM上执行,那么Java程式又如何要求VM去载入(Load)所指定的C组件呢?...

    JNI创建java对象

    这是我用于测试,主要用于jni创建java对象病操作

    JNI--java调用不同平台的动态链接库,dll,so,完美,全教程

    假如有一个现有的 .dll/.so 文件,假如使用 JNI 技术调用,我们首先需要另外使用 C 语言写一个 .dll/.so 共享库,使用 SUN 规定的数据结构替换 C 语言的数据结构,调用已有的 ? dll/so 中公布的函数。 然后再在 Java...

    java使用jni技术对硬件平台的资源进行监控

    java使用jni技术对硬件平台的CPU内存和网卡进行监控并生成报告。

    Java技术(JNI)实践

    很小的一个JNI调用实例,并且介绍一些JNI调用的一些常见问题的解决办法。

    有关java jni详解

    详细的讲解java jni的内幕和使用,希望对你有所帮助

    Android C、Java、JNI效率测试结果.doc

    world 文档,描述了Android g1环境,C、Java、JNI调用(C调Java、Java调C)基本运算、方法调用、字符串连接的效率测试结果。

Global site tag (gtag.js) - Google Analytics