Java 程序经验小结:谨慎的使用本地方法
1、写在开头
JNI 全称 Java Native Interface。Java 本地方法接口,它允许 Java 应用程序可以调用本地方法(native method),本地方法就是指用本地程序设计语言(C/C++等)编写的特殊方法。
维基百科是这样解释的:“当应用无法完全用 Java 编程语言实现的时候,(例如,标准 Java 类库不支持的特定平台特性或者程序库时),JNI 使得编程者能够编写 native 方法来处理这种情况”。
开讲前,我们先回顾下 JVM 的基本结构。根据《Java 虚拟机规范(Java SE 7 版)》。
JVM 的内存管理包括以下几个运行时数据区域:
程序计数器(Program Counter Register):当前线程执行的字节码指示器
Java 虚拟机栈(Java Virtual Machine Stacks):Java 方法执行的内存模型,每个方法会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
本地方法栈(Native Method Stack):(虚拟机使用到的)本地方法执行的内存模型。
Java 堆(Java Heap):虚拟机启动时创建的内存区域,唯一目的是存放对象实例,处于逻辑连续但物理不连续内存空间中。
方法区(Method Area):存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
运行时常量池(Runtime Constant Pool):方法区的一部分,存放编译器生成的各种字面值和符号引用。
2、本地方法的用途
本地方法主要提供三种用途:
提供“访问特定平台的机制”能力,如访问注册表(registry)和文件锁(file lock)
提供“访问遗留代码库”能力,进而访问遗留数据(legacy data)
编写应用程序中注重性能的部分,以提高系统的性能
使用本地方法访问特定于平台的机制是合法的。随着 JVM 的不断成熟,本地方法提供了越来越多以前只有在“宿主”平台才有的特性。例如,java 1.4 发行版新增的 java.util.prefs 包就提供了注册表的功能;1.6 发行版增加了 java.awt.SystemTray 提供了访问桌面系统托盘区的能力。
同时,使用本地方法来访问遗留代码也是合法的。
3、本地方法的重要性在下降
使用本地方法来提高性能的做法不值得提倡。早起的 jdk 发行版(1.3 之前),这样做法是必要的,但 JVM 实现变得越来越快了。对于大多数任务,现在即使不适应本地方法也能够获得与“使用本地方法”相当的性能了。
jdk 1.1 发行版增加了 java.math 时,BigInteger 是在一个用 C 编写的快速多精度运算库的基础上实现的。在当时,为了获取足够的性能,这样子做无可厚非
在 jdk 1.3 之后,BigInteger 完全用 Java 重写了,并且进行了精心的性能调优
其二,C/C++编写的程序是非安全的。所以,使用了本地方法的应用程序也不可以避免受到内存毁坏导致的错误
Java 是一门安全的语言(safe language),因为它对于缓冲区、数组越界、非法指针以及其他的内存破坏错误都自动免疫,而类似内存溢出或者指针异常等问题却始终困扰着 C/C++这样的非安全语言。
其三,因为本地语言是平台相关,使用本地方法的应用程序也不再是“自由移植”的。
其四,使用了本地方法的应用程序使得代码调试变得困难,在进入和退出本地方法时,需要额外的固定开销。所以,如果本地方法只是做了少量工作,非但没有起到优化性能的目的,反而降低了性能。
其五,需要“胶合代码”的本地方法编写起来单调乏味,代码可读性也低。
4、写在文末
如果你必须要使用本地方法来访问底层资源,或者遗留代码库,也要尽可能少用本地代码,并且进行全面测试。因为本地代码的一个 Bug 就可能破坏整个应用程序。
版权声明: 本文为 InfoQ 作者【后台技术汇】的原创文章。
原文链接:【http://xie.infoq.cn/article/f07f4e40cd69dcfc6d52097b6】。文章转载请联系作者。
评论 (2 条评论)