2. 4 访问 Java 对象
JNI 提供了一大批用来访问全局引用和局部引用的函数。这意味着无论虚拟机在内部如何表示 Java 对象,相同的本地方法实现都能工作。这就是为什么 JNI 可被各种各样的虚拟机实现所支持的关键原因。
通过不透明的引用来使用访问函数的开销比直接访问 C 数据结构的开销来得高。我们相信,大多数情况下,Java 程序员使用本地方法是为了完成一些重要任务,此时这种接口的开销不是首要问题。
2.4.1 访问基本类型数组
对于含有大量基本数据类型(如整数数组和字符串)的 Java 对象来说,这种开销将高得不可接受 (考虑一下用于执行矢量和矩阵运算的本地方法的情形便知)。对 Java 数组进行迭代并且要通过函数调用取回数组的每个元素,其效率是非常低的。
一个解决办法是引入“钉住”概念,以使本地方法能够要求虚拟机钉住数组内容。而后,该本地方法将接受指向数值元素的直接指针。但是,这种方法包含以下两个前提:
垃圾收集器必须支持钉住。
虚拟机必须在内存中连续存放基本类型数组。虽然大多数基本类型数组都是连续存放的,但布尔数组可以压缩或不压缩存储。因此,依赖于布尔数组确切存储方式的本地方法将是不可移植的。
我们将采取折衷方法来克服上述两个问题。
首先,我们提供了一套函数,用于在 Java 数组的一部分和本地内存缓冲之间复制基本类型数组元素。这些函数只有在本地方法只需访问大型数组中的一小部分元素时才使用。
其次,程序员可用另一套函数来取回数组元素的受约束版本。记住,这些函数可能要求 Java 虚拟机分配存储空间和进行复制。虚拟机实现将决定这些函数是否真正复制该数组,如下所示:
如果