JNI - 在 Java 和本机代码之间传递大量数据
我正在努力实现以下目标:
1)我在java端有一个字节数组,表示图像。
2)我需要让我的本机代码访问它。
3)本机代码使用GraphicsMagick对此图像进行解码,并通过调用resize来创建一堆缩略图。它还计算图像的感知哈希,该哈希是向量或unint8_t数组。
4)一旦我把这个数据返回到Java端,不同的线程会读取它。缩略图将通过 HTTP 上传到某些外部存储服务。
我的问题是:
1)将字节从Java传递到我的本机代码的最有效方法是什么?我可以将其作为字节数组访问。与此处的字节数组相比,我没有看到将其作为字节缓冲区(包装此字节数组)传递的任何特别优势。
2)将这些缩略图和感知哈希返回给java代码的最佳方法是什么?我想到了几个选项:
(i)我可以在Java中分配一个字节缓冲区,然后将其传递给我的本机方法。然后,本机方法可以写入它并在完成后设置限制,并返回写入的字节数或指示成功的一些布尔值。然后,我可以对字节缓冲区进行切片和切块,以提取不同的缩略图和感知哈希,并将其传递到将上传缩略图的不同线程。这种方法的问题在于我不知道要分配什么大小。所需的大小将取决于生成的缩略图的大小,我事先不知道以及缩略图的数量(我事先知道这一点)。
(ii)一旦我知道所需的大小,我还可以在本机代码中分配字节缓冲区。我可以根据自定义打包协议将 Blob 压缩到正确的区域,并返回此字节缓冲区。(i) 和 (ii) 似乎都很复杂,因为自定义打包协议必须指示每个缩略图的长度和感知哈希。
(iii) 定义一个 Java 类,该类具有缩略图字段:字节缓冲区数组和感知哈希:字节数组。当我知道所需的确切大小时,我可以在本机代码中分配字节缓冲区。然后,我可以将来自我的GraphicsMagick blob的字节复制到每个字节缓冲区的直接地址。我假设还有一些方法来设置在字节缓冲区上写入的字节数,以便java代码知道字节缓冲区有多大。设置字节缓冲区后,我可以填写我的Java对象并返回它。与(i)和(ii)相比,我在这里创建了更多的字节缓冲区和Java对象,但我避免了自定义协议的复杂性。(i),(ii)和(iii)背后的基本原理 - 鉴于我对这些缩略图的唯一目的是上传它们,我希望在通过NIO上传它们时保存一个带有字节缓冲区(与字节数组)的额外副本。
(iv) 定义一个 Java 类,该类具有用于缩略图的字节数组(而不是字节缓冲区)和用于感知哈希的字节数组。我在我的本机代码中创建这些Java数组,并使用SetByteArrayRegion从我的GraphicsMagick blob复制字节。与以前的方法相比,缺点是现在在上传此字节数组时将此字节数组从堆复制到某个直接缓冲区时,Java land中将有另一个副本。不确定我是否会在这里保存任何复杂性与(iii)的东西。
任何建议都会很棒。
编辑:@main提出了一个有趣的解决方案。我正在编辑我的问题以跟进该选项。如果我想像@main建议的那样将本机内存包装在 DirectBuffer 中,我怎么知道何时可以安全地释放本机内存?