假设我有一个包含N个元素的C字符串数组。我的目标是使用JNI将该数组传递给Java函数,并返回一个等长的新字符串数组回到C空间。目前我做如下:将C字符串数组移动到Java空间的更有效方法
- 使用NewObjectArray以产生长度为N
- 调用NewStringUTF/SetObjectArray N倍的Java对象阵列,至框每个单独的C字符串到Java对象阵列。
- 调用copyStrArr(下面的源代码)。
- 用malloc分配长度为N的(char *)数组。
- 调用GetObjectArrayElement/GetStringUTFChars N次,以从返回的Java Object数组中解开每个单独的Java String。
仅供参考,Java代码看起来是这样的:
public static String[] copyStrArr(String []inArr)
{
String []outArr = new String[inArr.length];
for(int _i = 0; _i < outArr.length; _i++) {
outArr[_i] = inArr[_i]; /* Normally real work would be done here */
}
return outArr;
}
在“真实”的情况下,实际的工作将里面的for循环来完成,但对于标杆,我们要做的仅仅是副本数据。
对于较大的N值,这很慢。不敬虔缓慢。当从C到Java移动类似大小的整数或双精度数组并返回时,它的运行速度比String []大约快70倍。大约99.5%的时间花在装箱和拆箱数据上。在原始情况下,JNI提供了{Set,Get} ArrayRegion函数,可以将原始数组从C空间批量复制到Java空间并返回,速度更快。
有人建议我使用byte []作为中介,将数据导入Java空间,然后在Java中进行单独的String对象装箱(JVM可以优化事物)。基准测试表明,这比原来的测试表现稍差,将大部分开销转移到Java。部分原因可能是我可能无法在Java中以最优方式拆箱/装箱byte []。我做如下:
- 分配一个充分大的字节[]与NewByteArray
- 调用SetByteArrayRegion N次来填充字节[]
- 调用copyBytArray(下面源)
- 调用GetByteArrayRegion和复制整个结果返回C空间
- 分配一个足够大的数组(char *)
- 将N个字符串中的每一个从结果中复制到新分配的数组中。
我的Java代码如下所示:
public static byte[] copyBytArr(byte []inArr)
{
String[] tokInArr = new String(inArr, UTF8_CHARSET).split("\0");
String []tokOutArr = new String[tokInArr.length];
int len = 0;
for(int _i = 0; _i < tokOutArr.length; _i++) {
tokOutArr[_i] = tokInArr[_i]; /* Normally real work would be done here */
len += (tokInArr[_i].length() + 1);
}
byte[] outArr = new byte[len];
int _j = 0;
for(int _i = 0; _i < tokOutArr.length; _i++) {
byte[] bytes = tokOutArr[_i].getBytes(UTF8_CHARSET);
for(int _k = 0; _k < bytes.length; _k++) {
outArr[_j++] = bytes[_k];
}
outArr[_j++] = '\0';
}
return outArr;
}
在这个测试的开销约55%是在Java中度过的,其余的则花在装箱/拆箱。
有人提出我的一些开销与我在C中使用UTF-8数据有关,因为Java使用UTF-16。这是不可避免的。
有没有人有任何想法,我可能会更有效地去做这件事?
移动大量数据总是很慢,并且在JNI边界上移动任何东西都很慢。你真的必须这样做吗? – EJP
可以用char或其他东西代替String对象吗?因为原始类型处理速度比JVM中的对象更快 – user4127
@Radiodef我不希望我的名字与任何'JNI中没有任何内容是有效的'声明相关联。无效的是将数据移动到JNI边界,这是因为它*是*数据移动。如果您使用100%Java或100%C,则不必移动任何东西。 JNI中的大部分内容都非常高效,在某些情况下效率也很高,因为没有错误检查。 – EJP