使用JNI能否提高反射性能?

3

我的代码中有大量的反射查找,所以我想办法进行改进。

这是我 jni setter 方法的示例:

JNIEXPORT jobject JNICALL 
Java_org_orman_mapper_Model_fieldSetFloat(JNIEnv * env, jobject  obj, jobject model, jstring field_name, jstring field_type, jfloat value, jclass clazz)
{
    const char* utf_string_name = (*env)->GetStringUTFChars (env, field_name, 0);
    const char* utf_string_type = (*env)->GetStringUTFChars (env, field_type, 0);

    jfieldID id = (*env)->GetFieldID(env, clazz, utf_string_name, utf_string_type);
    (*env)->SetFloatField(env, model, id, value);
    return model;
}

SetFloatField这样的调用本质上是否跳过任何Java安全检查?

我没有注意到性能上的任何提升。


我预计 GetStringUTFChars 是迄今为止最昂贵的函数。你能在这里缓存 jfieldID 吗?如果你想绕过安全检查,可以调用 Member.setAccessible(true);,这样即使你有权限,它也会更快。 - Peter Lawrey
@PeterLawrey,这就是我现在正在看的。 - kaneda
不确定它是否比JNI更快,但这是一种用最少的努力加速反射的方法。 ;) 您可以查看MethodHandles,具体取决于您的JVM以及如何使用它,它可能会更快。 - Peter Lawrey
@PeterLawrey,MethodHandles是来自jdk7的吗?不幸的是,我只能使用版本6。 - kaneda
1
我不确定在任何情况下设置字段会更快。 - Peter Lawrey
1个回答

6
使用JNI可以稍微提高反射性能,但你需要使用JNI来访问对象内部的数据,而这样做会导致一些不必要的访问检查失效。与此相反,反射方法及其调用序列的实现可能已被优化,在普通JNI方法无法实现的方面得到改进。例如,它们可能被实现为直接访问相关数据结构,而不是使用平台无关的JNI API。或者JIT编译器可能将对某些“本质”本地方法的调用视为特殊情况,并使用更快的调用序列。请注意,这都是假设……但在某些JVM中,某些核心方法的本机实现已经得到了特别处理以使它们更快。


然而,我的建议是,如果你用普通的非反射Java代码替换反射代码(无论是手写的代码、作为源代码生成并编译的代码,还是作为字节码生成的代码),你将获得更好的性能(比反射或JNI快一个数量级或更多)。一旦你拥有字节码,JIT编译器将能够生成优化的本机代码,比起使用反射或JNI要快得多。

因此,与其用JNI代码(及其相关问题)替换反射,不如用纯字节码的东西来替换它。


你是指在运行时生成字节码吗?我读过一篇文章说这是个解决方案,但我发现很难实现。如果我能通过字节码操作来设置字段,我会赌那种方式的。 - kaneda
我同意Stephen的观点。我不认为有任何理由用JNI编写这段代码。你可以用大约四行Java代码完成它。 - user207421
1
应用程序的性质将决定是在编译时、加载时还是运行时生成。如果直接生成字节码太困难,考虑其他替代方案。 - Stephen C

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接