关闭

Android Java与JNI层互传数据总结

标签: androidJNI数据传递
1714人阅读 评论(0) 收藏 举报
分类:

在开发中常常会遇到从Java层传递数据到JNI层,然后在JNI拿到数据后就可以用C语言进行操作了,操作完数据后通常还需要把处理后的数据传回Java层。下面分别进行小结。

从Java层传到JNI层

  • 使用GetByteArrayRegion的方式
    该方法的本质是将Java端数组数据拷贝到本地的数组中,所以在JNI对数据修改后Java端的数据并没有改变。
  • 使用GetPrimitiveArrayCritical
    GetPrimitiveArrayCritical 表面上可以得到底层数据指针,在JNI层修改数组时Java层的数据也会变。But,如果只使用GetPrimitiveArrayCritical获取数据,程序运行一段时间内存会crash。所以,使用GetPrimitiveArrayCritical时必须使用ReleasePrimitiveArrayCritical ,通过测试发现当数据量大时执行ReleasePrimitiveArrayCritical会非常耗时。

从JNI层传到Java层

  • 把Jni层的数组传递到Java层,一般有两种方法,一种是通过native函数的返回值来传递,另一种是通过jni层回调java层的函数来传递,后者多用于jni的线程中或是数据量较大的情况。无论哪种方法,都离不开 SetByteArrayRegion 函数,该函数将本地的数组数据拷贝到了 Java 端的数组中。

注意上面的方式中都会涉及到内存拷贝,根据实战经验,在Android系统中,一旦数据量变大,拷贝一次内存将非常耗时。所以上述方式在追求效率时不推荐使用。解决的方法可以尝试让JAVA层和JNI共享内存的方式。最后找到了两种方式。


Java层和JNI层共享内存空间

  • 使用GetByteArrayElements方式
    该方式是指针的形式,将本地的数组指针直接指向Java端的数组地址,其实本质上是JVM在堆上分配的这个数组对象上增加一个引用计数,保证垃圾回收的时候不要释放,从而交给本地的指针使用,使用完毕后指针一定要记得通过ReleaseByteArrayElements进行释放,否则会产生内存泄露。

    unsigned char* psrcImg = (unsigned char*)(env->GetByteArrayElements(srcImg,0));  
    unsigned char* pBufferI420 = (unsigned char*) (env->GetByteArrayElements(dstImg,0));
    
    if (psrcImg == NULL || pBufferI420 == NULL)
    {
      return -1;
    }
    env->ReleaseByteArrayElements(srcImg,(jbyte*)psrcImg,0);
    env->ReleaseByteArrayElements(dstImg,(jbyte*)pBufferI420,0);

    注意if那里最好加上,网上查了说,get那里可能失败,失败得到的psrcImg是NULL,Release的时候程序就会崩。

  • Direct Buffer 方式传递。
    Java和Jni层的数组传递还有一个比较重要的方式,就是通过Direct Buffer来传递,这种方式类似于在堆上创建创建了一个Java和Jni层共享的整块内存区域,无论是Java层或者Jni层均可访问这块内存,并且Java端与Jni端同步变化,由于是采用的是共享内存的方式,因此相比于普通的数组传递,效率更高,但是由于构造/析构/维护这块共享内存的代价比较大,所以小数据量的数组建议还是采用上述方式,Direct Buffer方式更适合长期使用频繁访问的大块内存的共享。具体可使用GetDirectBufferAddress获得共享的内存地址。

综上,在图像算法开发中,我采用了GetByteArrayElements-ReleaseByteArrayElements的方式来传递图像数据。此外,在开发Android上的算法时,尽量避免内存拷贝,特别是JNI层。

Reference:
http://blog.csdn.net/xinchen200/article/details/25333047
http://zsaber.com/blog/p/107

0
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

Jni中C++和Java的参数传递

利用VC++6.0实现JNI的最简单的例子
  • ymangu
  • ymangu
  • 2014-04-29 15:29
  • 1681

androidjni编程,java和c层的互相通信传递数据

  • 2016-05-09 10:15
  • 14.96MB
  • 下载

JNI在C++与java间传递各种数据格式举例

JniMethodInfo minfo;//JniHelper    /* 测试用方法 */ bool isHave = JniHelper::getStaticMethodInfo(minfo,...
  • keven418440201
  • keven418440201
  • 2016-07-15 14:27
  • 1009

Android使用JNI实现Java与C之间传递数据

介绍Java如何将数据传递给C和C回调Java的方法。  java传递数据给C,在C代码中进行处理数据,处理完数据后返回给java。C的回调是Java传递数据给C,C需要用到Java中的某个方法,就需...
  • furongkang
  • furongkang
  • 2011-10-10 01:46
  • 40194

java(JVM)结束时释放JNI资源(Runtime.addShutdownHook)

如下代码中cmjnidrv是一个动态库,CodeCacheManager在类加载时就自动将cmjnidrv加载进来。cmjnidrv中有多个独立的线程在运行并申请了大量的内存. release()是...
  • 10km
  • 10km
  • 2016-01-05 11:20
  • 1271

NDK 之 JNI数据传输

1 基本数据类型的传输 上层定义一个native的方法,需要一个int 参数 ,返回一个int值 JNI 对应上层的方法 , 打印出上层 传输下来的 int数据,并返回 int数据 上层 收到 ...
  • zhaowb82
  • zhaowb82
  • 2012-02-18 11:32
  • 2389

java Dao层对数据库操作总结

一、获取数据库连接 Connection con = null; try{     con =this.getSessionFactory.getCurrentSession().connection...
  • u011300808
  • u011300808
  • 2016-06-12 10:51
  • 2110

用JNI从C传递结构体到JAVA

直接上C的实现 typedef struct Foo {     int len;     char name[100]; } Foo_t; ...
  • vbLittleBoy
  • vbLittleBoy
  • 2013-09-17 10:52
  • 9220

JNI层与Java层结构体传递

JNI层与Java层结构体传递 最近在做移动终端开发,需要把native层C++一些统计数据传递给java层使用,在做这部分功能的时候发现JNI层与Java层结构体以及内嵌结构体传递在网上的资料甚少,...
  • zdy_ruoshui
  • zdy_ruoshui
  • 2015-03-08 12:13
  • 2519

Java JNI实现原理初探

前言 写这个是出于好奇。 我们知道cpu只认得 "0101101" 类似这种符号, C、C++ 这些代码最终都得通过编译、汇编成二进制代码,cpu才能识别。而Java比C、C++又多了一...
  • hackooo
  • hackooo
  • 2015-09-12 17:31
  • 8408
    个人资料
    • 访问:182625次
    • 积分:2760
    • 等级:
    • 排名:第15013名
    • 原创:86篇
    • 转载:6篇
    • 译文:0篇
    • 评论:73条
    文章分类
    最新评论