首页>java频道>java教程>正文
关于Java JNI深度分析与实践

www.zige365.com 2010-6-7 11:16:50 点击:发送给好友 和学友门交流一下 收藏到我的会员中心
  • if ((*env)->ExceptionCheck(env)) {   
  • return ERR_CALL_STATIC_METHOD_FAILED;   
  • 当我们每次希望调用方法时查找类和方法 ID 都会产生六个本机调用,而不是第一次缓存类和方法 ID 时需要的两个调用。

    缓存会对您应用程序的运行时造成显著的影响。考虑下面两个版本的方法,它们的作用是相同的。清单 2 使用了缓存的字段 ID:

    清单 2. 使用缓存的字段 ID

    1.      int sumValues2(JNIEnv* env, jobject obj, jobject allValues){   
    2. jint avalue = (*env)->GetIntField(env, allValues, a);   
    3. jint bvalue = (*env)->GetIntField(env, allValues, b);   
    4. jint cvalue = (*env)->GetIntField(env, allValues, c);   
    5. jint dvalue = (*env)->GetIntField(env, allValues, d);   
    6. jint evalue = (*env)->GetIntField(env, allValues, e);   
    7. jint fvalue = (*env)->GetIntField(env, allValues, f);   
    8. return avalue + bvalue + cvalue + dvalue + evalue + fvalue;   

    清单 3. 未缓存字段 ID

    1.    int sumValues2(JNIEnv* env, jobject obj, jobject allValues){   
    2. jclass cls = (*env)->GetObjectClass(env,allValues);   
    3. jfieldID a = (*env)->GetFieldID(env, cls, "a", "I");   
    4. jfieldID b = (*env)->GetFieldID(env, cls, "b", "I");   
    5. jfieldID c = (*env)->GetFieldID(env, cls, "c", "I");   
    6. jfieldID d = (*env)->GetFieldID(env, cls, "d", "I");   
    7. jfieldID e = (*env)->GetFieldID(env, cls, "e", "I");   
    8. jfieldID f = (*env)->GetFieldID(env, cls, "f", "I");   
    9. jint avalue = (*env)->GetIntField(env, allValues, a);   
    10. jint bvalue = (*env)->GetIntField(env, allValues, b);   
    11. jint cvalue = (*env)->GetIntField(env, allValues, c);   
    12. jint dvalue = (*env)->GetIntField(env, allValues, d);   
    13. jint evalue = (*env)->GetIntField(env, allValues, e);   
    14. jint fvalue = (*env)->GetIntField(env, allValues, f);   
    15. return avalue + bvalue + cvalue + dvalue + evalue + fvalue 

    清单 2 用 3,572 ms 运行了 10,000,000 次。清单 3 用了 86,217 ms — 多花了 24 倍的时间。

    触发数组副本

    JNI 在 Java 代码和本机代码之间提供了一个干净的接口。为了维持这种分离,数组将作为不透明的句柄传递,并且本机代码必须回调 JVM 以便使用 set 和 get 调用操作数组元素。Java 规范让 JVM 实现决定让这些调用提供对数组的直接访问,还是返回一个数组副本。举例来说,当数组经过优化而不需要连续存储时,JVM 可以返回一个副本。(参见 参考资料 获取关于 JVM 的信息)。

    随后,这些调用可以复制被操作的元素。举例来说,如果您对含有 1,000 个元素的数组调用 GetLongArrayElements(),则会造成至少分配或复制 8,000 字节的数据(每个 long 1,000 元素 * 8 字节)。当您随后使用 ReleaseLongArrayElements() 更新数组的内容时,需要另外复制 8,000 字节的数据来更新数组。即使您使用较新的 GetPrimitiveArrayCritical(),规范仍然准许 JVM 创建完整数组的副本。

    GetTypeArrayRegion() 和 SetTypeArrayRegion() 方法允许您获取和更新数组的一部分,而不是整个数组。通过使用这些方法访问较大的数组,您可以确保只复制本机代码将要实际使用的数组部分。

    本新闻共3页,当前在第2页  1  2  3  

    我要投稿 新闻来源: 编辑: 作者:
    相关新闻
    浅谈Java和Oracle实现BLOB字段的字符串读取
    Java多线程编程实战要点
    浅谈Java内部类使用的四点建议
    jQuery框架与构造对象
    Java终止函数详解