当前位置: 首页 > news >正文

NDK开发与实践(入门篇微课视频版)

9.3 DirectBuffer的使用场景
当使用byte[]数组时,Java代码需要将数据从Java堆复制到原生内存(例如,通过JNI的SetByteArrayRegion()或GetByteArrayRegion()函数),然后原生代码才能访问这些数据。这种数据复制操作可能会带来额外的性能开销。在某些实现中,可以使用GetByteArrayElements()和 GetPrimitiveArrayCritical()函数获取指向托管堆中原始数据的实际指针,但在其他实现中,它会在原生堆上分配缓冲区并复制数据,所以,byte[]传递是否能获得真正的原始数据的指针,取决于虚拟机的实现,而直接字节缓冲区允许原生代码直接访问其内存区域,无须进行这种复制操作。
9.3.1 大数据量的IO密集型操作
对于需要处理大量数据的IO密集操作,如文件读写、网络通信等,DirectBuffer可以
显著提高性能。由于DirectBuffer的内存分配在JVM堆外,因此可以避免在Java堆内存和操作系统之间复制数据的需要,从而减少了数据处理的时间和CPU的负载。
9.3.2 长期使用的数据
对于那些需要长期使用的数据,使用DirectBuffer可以避免频繁地创建和销毁堆内
Buffer所带来的额外开销。由于DirectBuffer的生命周期内的内存地址都不会再发生更改,因此内核可以安全地对其进行访问。
9.3.3 对内存管理有特殊要求的场景
DirectBuffer的使用降低了垃圾收集的压力,因为它们不受JVM垃圾收集的直接管
理。这在一些对内存管理有特殊要求的场景中可能非常有用,例如需要避免频繁垃圾收集导致的性能波动或延迟。

9.3.4 需要直接访问操作系统内存资源的场景
DirectBuffer提供了一种高效的方式来直接访问和操作系统级别的内存资源。这种方式允许Java应用程序能够更接近操作系统的底层,提供了更为高效的数据处理能力。

9.4 DirectBuffer的使用案例
示例代码将演示在原生代码中申请缓冲区,并通过JNI接口使其可被Java代码访问。在Java端,利用获得到的缓冲区的引用将数据高效地传递到原生代码中。同时,示例代码将记录两种传递方式分别运行10000000次的耗时。

代码如下:
//第9章/MainActivity.java
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
static {
System.loadLibrary("directbuffer");
}

ByteBuffer mByteBuffer;
@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//获得native中申请的缓冲区mByteBuffer = getNativeByteBuffer();//申请一个byte数组byte[] bytes = new byte[10240];//初始化数组内容for (int i = 0; i < 10240; i++) {bytes[i] = (byte) i;}//将byte数组放到bytebuffer中mByteBuffer.put(bytes);int count = 10000000;//打印时间Log.e(TAG, "onCreate: sendData start time: "  + SystemClock.currentThreadTimeMillis());while (count > 0){//通知原生代码操作数据sendData();count --;}Log.e(TAG, "onCreate: sendData end time: "  + SystemClock.currentThreadTimeMillis());count = 1000000;//打印时间Log.e(TAG, "onCreate: setByteData start time: "  + SystemClock.currentThreadTimeMillis());while (count > 0){//将byte[]传递到原生代码中setByteData(bytes);count --;}Log.e(TAG, "onCreate: setByteData end time: "  + SystemClock.currentThreadTimeMillis());
}/*** 获取native申请的DirectBuffer* @return  DirectBuffer*/
public native ByteBuffer getNativeByteBuffer();/*** 通知原生代码操作数据*/
public native void sendData();/*** 使用byte[]数组传递方式* @param data byte[]*/
public native void setByteData(byte[] data);

}

原生代码实现代码如下:
//第9章/native-lib.c

include <jni.h>

include <string.h>

include <malloc.h>

include <android/log.h> //添加头文件

define LOG_TAG "jni" //定义TAG

define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, VA_ARGS)

unsigned char *gl_buffer = NULL; //DirectBuffer地址
unsigned int gl_capacity; //DirectBuffer 容量

unsigned char buffer[10240] = {0}; //用来模拟数据的复制

JNIEXPORT jobject JNICALL
Java_com_example_directbuffer_MainActivity_getNativeByteBuffer(JNIEnv *env, jobject thiz) {
if (NULL == gl_buffer){
gl_buffer = malloc(10240);
}

return (*env)->NewDirectByteBuffer(env, gl_buffer, 10240);

}

JNIEXPORT void JNICALL
Java_com_example_directbuffer_MainActivity_sendData(JNIEnv *env, jobject thiz) {
//由于是DirectBuffer,这里可以直接使用gl_buffer,无须复制
}

JNIEXPORT void JNICALL
Java_com_example_directbuffer_MainActivity_setByteData(JNIEnv env, jobject thiz, jbyteArray data) {
//模拟数据的使用,将数组内容复制到gl_buffer中才能使用
(
env)->GetByteArrayRegion(env, data, 0, 10240, gl_buffer);
}

运行结果如下:

//使用DirectBuffer,10000000次执行耗时66ms
sendData start time: 117
sendData end time: 183

//直接传递byte[],10000000次执行耗时2021ms
setByteData start time: 183
setByteData end time: 2204

对于不同次数比较的运行结果,见表9-1。

表 9 1 运行结果比较
运行次数 DirectBuffer byte[] 差值(ms)
1000 0 0 0
10000 3 4 1
100000 12 24 12
1000000 18 208 190
10000000 66 2021 1955

从运行结果可以看出,随着运行次数的增加,相较于使用byte[],使用DirectBuffer对性能的提升也就越明显。

http://www.hskmm.com/?act=detail&tid=25327

相关文章:

  • 调了很久的代码总结
  • CF700E
  • 价值弥漫:“AI元人文”的场域革命与共生之路
  • k8s之pod概念
  • CF 1055 Div.1+Div.2
  • 2026 NOI 做题记录(五)
  • ARC 207 (Div.1)
  • “齐俊杰投资智能体”更新完了9月份的资料
  • LVS+Keepalived高可用群集 - 指南
  • luogu P1020 [NOIP 1999 提高组] 导弹拦截
  • RabbitMQ 离线安装
  • Nginx 离线安装
  • docker 离线安装
  • uniapp 转回tabbar页面
  • 第十一届中国大学生程序设计竞赛网络预选赛 魔塔
  • JDK 离线安装
  • minio 离线安装
  • HbuilderX 将 h5转成uniapp的一些记录.19127294
  • 银行同业存单产品的筛选方法
  • deepseek 私有部署文档
  • MySQL运维及开发规范
  • 短视频平台差异视角下开源AI智能名片链动2+1模式S2B2C商城小代码的适配性研究——以抖音与快手为例
  • 异步读写mysql依赖pymysql (asyncio/ aiomysql)
  • Linux发行版切换技术全解析
  • 手把手教你用 Docker 部署 Redis
  • 悟空博弈单元(WBUC)与广域统一计算(WAUC)研究:价值共生的技术基石——声明Ai研究
  • 掌握形式验证工具,提升芯片验证效率
  • 长租公寓的生存越来越难了 - 智慧园区
  • Spring Boot中保存前端上传的图片 - 教程
  • P2724 [IOI 1998 / USACO3.1] 联系 Contact 做题笔记