使用 JNI 中的 GetDirectBufferAddress
我试图了解如何从 JNI 层使用 GetDirectBufferAddress
.为了理解,我构建了一个非常简单的示例:
public class my_image_info {静止的 {System.loadLibrary(my_jni");}私有 java.nio.ByteBuffer image_info_bb;本机静态无效初始化(java.nio.ByteBuffer bb);我的图像信息(){image_info_bb = java.nio.ByteBuffer.allocateDirect(5 * 4);初始化(image_info_bb);}公共 java.nio.ByteBuffer getBB() {返回 image_info_bb;}静态公共无效主要(字符串argv []){my_image_info fii = new my_image_info();java.nio.ByteBuffer bb = fii.getBB();System.out.println("1:" + bb.getInt(0));System.out.println("2:" + bb.getInt(4));System.out.println("3:" + bb.getInt(8));System.out.println("4:" + bb.getInt(12));System.out.println("5:" + bb.getInt(16));}
然后从原生 JNI 层:
JNIEXPORT void JNICALL Java_my_1image_1info_initc(JNIEnv *env, jclass cls, jobject jobj){int *iBuf = (*env)->GetDirectBufferAddress(env, jobj);iBuf[0] = -2;iBuf[1] = -1;iBuf[2] = 0;iBuf[3] = 1;iBuf[4] = 2;}
如果我在这里使用 openjdk 运行这个示例(debian/linux wheezy amd64):
$ java -versionjava版本1.6.0_34"OpenJDK 运行时环境 (IcedTea6 1.13.6) (6b34-1.13.6-1~deb7u1)OpenJDK 64 位服务器 VM(内部版本 23.25-b01,混合模式)
这是我看到的:
1: -167772172:-13:04:167772165:33554432
我了解索引 2 的值 &3. 但是所有其他值对我来说都没有任何意义,我本来希望是这样的:
1: -22:-13:04:15:2
我从 JNI 中的 ByteBuffer
用法中误解了什么?
我从文档中遗漏的是,默认情况下 java.nio.ByteBuffer
实际上是使用 BIG_ENDIAN
字节顺序.这解释了我在 LITTLE_ENDIAN
系统上看到的行为.请参阅参考 此处.p>
我的代码现在读作:
image_info_bb = java.nio.ByteBuffer.allocateDirect(5 * 4);image_info_bb.order(java.nio.ByteOrder.LITTLE_ENDIAN);
似乎默认情况下它始终是 BIG_ENDIAN
,并且到目前为止还没有努力为 LITTLE_ENDIAN
提供 API,如错误报告中所述 这里 (JDK-5043362 : (bf) NewDirectByteBuffer 总是有订单 ByteOrder.BIG_ENDIAN).
最近更新了文档以反映:
- JDK-8225152:发行说明:JNI NewDirectByteBuffer 创建直接缓冲区,即 java.nio.ByteOrder.BIG_ENDIAN
I am trying to understand how to use GetDirectBufferAddress
from the JNI layer. To understand I've build a very simple example:
public class my_image_info {
static {
System.loadLibrary("my_jni");
}
private java.nio.ByteBuffer image_info_bb;
native static void initc( java.nio.ByteBuffer bb );
my_image_info()
{
image_info_bb = java.nio.ByteBuffer.allocateDirect( 5 * 4 );
initc( image_info_bb );
}
public java.nio.ByteBuffer getBB() {
return image_info_bb;
}
static public void main(String argv[]) {
my_image_info fii = new my_image_info();
java.nio.ByteBuffer bb = fii.getBB();
System.out.println("1: " + bb.getInt(0));
System.out.println("2: " + bb.getInt(4));
System.out.println("3: " + bb.getInt(8));
System.out.println("4: " + bb.getInt(12));
System.out.println("5: " + bb.getInt(16));
}
And then from the native JNI layer:
JNIEXPORT void JNICALL Java_my_1image_1info_initc
(JNIEnv *env, jclass cls, jobject jobj)
{
int *iBuf = (*env)->GetDirectBufferAddress(env, jobj);
iBuf[0] = -2;
iBuf[1] = -1;
iBuf[2] = 0;
iBuf[3] = 1;
iBuf[4] = 2;
}
If I run this example over here (debian/linux wheezy amd64) with openjdk :
$ java -version
java version "1.6.0_34"
OpenJDK Runtime Environment (IcedTea6 1.13.6) (6b34-1.13.6-1~deb7u1)
OpenJDK 64-Bit Server VM (build 23.25-b01, mixed mode)
Here is what I see:
1: -16777217
2: -1
3: 0
4: 16777216
5: 33554432
I understand the values for index 2 & 3. But all other values do not make any sense to me, I would have expected something like:
1: -2
2: -1
3: 0
4: 1
5: 2
What did I misunderstood from the ByteBuffer
usage in JNI?
What I missed from the documentation is that by default java.nio.ByteBuffer
is actually using BIG_ENDIAN
byte order. Which explains the behavior I was seeing on my LITTLE_ENDIAN
system. See ref here.
My code now reads as:
image_info_bb = java.nio.ByteBuffer.allocateDirect( 5 * 4 );
image_info_bb.order( java.nio.ByteOrder.LITTLE_ENDIAN );
It appears that by default it is always BIG_ENDIAN
, and no effort has been made so far to provide an API for LITTLE_ENDIAN
, as explained in the bug report here (JDK-5043362 : (bf) NewDirectByteBuffer always has order ByteOrder.BIG_ENDIAN).
Documentation has been updated recently to reflect that:
- JDK-8225152 : Release Note: JNI NewDirectByteBuffer Creates Direct Buffer That Is java.nio.ByteOrder.BIG_ENDIAN
相关文章