原生I/O在缓冲区、大规模网络和文件I/O及字符集支持方面的性能有所改进。JNI提供了在原生代码中使用NIO的函数。与数组操作相比,NIO缓冲区的数据传送性能较好,更适合在原生代码和java应用程序之间传送大量数据。
1.创建直接字节缓冲区
原生代码可以创建java应用程序使用的直接字节缓冲区,该过程是以提供一个原生C字节组为基础。
//基于给定C字节数组创建字节缓冲区
unsigned char* buffer =(unsigned char*)malloc(1024);
jobject directBuffer;
directBuffer = (*env)->NewDirectByteBuffer(env,buffer,1024);
注意
原生方法中的内存分配超出了虚拟机的管理范围,切不能用虚拟机的垃圾回收原生方法中的内存。原生函数应该通过释放未使用的内存分配以避免内存泄漏来正确管理内存。
2.直接字节缓冲区获取
java应用程序中也可以创建直接字节缓冲区,在原生代码中调用GetDirectBufferAddress函数可以获得原生字节数组的内存地址
//通过Java字节缓冲区获取原生字节码
unsigned char* buffer;
buffer = (unsigned char*)(*env)
->GetDirectBufferAddress(env,directBuffer)
3.访问域
Java有两大访问域:例域和静态域类的每个实例域都有自己的实例域副本,而一个类的所有实例共享同一个静态域。
3.1获取域ID
//用引用对象获得类
jclass clazz;
clazz = (*env)->GetObjectClass(env,instance);
有两个额获得域ID的函数分别适用于不同类型域,函数分别为GetFieldId,GetStaticFieldID
jfieldID instanceFieldId;
instanceFieldId = (*env)->GetFieldID(env,clazz,"instanceField","Ljava/lang/String");
jfieldID staticFieldId;
staticField = (*env)->GetStaticFieldID(env,clazz,"staticField","Ljava/lang/String");
两个函数的最后一个参数是Java中表示域类型的域描述符。
“Ljava/lang/String”表示域类型是String。
3.2获取域
在获得域ID之后可以通过GetField函数获得实际的实例域。
jstring instanceField;
instanceField= (*env)->GetObjectField(env,instance,instanceFieldId);
jstring staticField;
staticField = (*env)->GetStaticObjectField(env,clazz,staticField);
获得单个域值需要调用两到三个JNI函数,原生代码回到java中获得每个单独的域值,这给应用程序增加了额外的负担,进而导致了性能下降。强烈建议将所有需要的参数传递给原生方法调用,而不是让原生代码回到Java中。