在路上

 找回密码
 立即注册
在路上 站点首页 学习 查看内容

JNI Construction Benchmark

2017-2-7 13:39| 发布者: zhangjf| 查看: 700| 评论: 0

摘要: JNI Construction Benchmark We provide the code for a small benchmark to compare the costs of JNI object creation, and then present theresults. The code contrasts three different approaches to constr ...
JNI Construction Benchmark

We provide the code for a small benchmark to compare the costs of JNI object creation, and then present theresults.

The code contrasts three different approaches to constructing a Java Object that wraps a C++ object (which it has to construct). Such a scenario is common when writing a Java API wrapper for an existing C++ project.

Scenario 1 - By Call

From Java we call a JNI C++ member function to construct the C++ object and return a jlong which represents the memory pointer to the C++ object.

  1. public class FooByCall extends NativeBackedObject {
  2. public FooByCall() {
  3. super();
  4. this._nativeHandle = newFoo();
  5. }
  6. private native long newFoo();
  7. ...
复制代码
  1. jlong Java_com_evolvedbinary_jni_consbench_FooByCall_newFoo(JNIEnv* env, jobject jobj) {
  2. consbench::Foo* foo = new consbench::Foo();
  3. return reinterpret_cast<jlong>(foo);
  4. }
复制代码
Scenario 2 - By Call, Static

Similar to Scenario 1 , except that we use a static call to a JNI C++ function.

  1. public class FooByCallStatic extends NativeBackedObject {
  2. public FooByCallStatic() {
  3. super();
  4. this._nativeHandle = newFoo();
  5. }
  6. private static native long newFoo();
  7. ...
复制代码
  1. jlong Java_com_evolvedbinary_jni_consbench_FooByCallStatic_newFoo(JNIEnv* env, jclass jcls) {
  2. consbench::Foo* foo = new consbench::Foo();
  3. return reinterpret_cast<jlong>(foo);
  4. }
复制代码
Scenario 3 - By Call, Invoke

Similar to Scenario 1 , however instead of returning a jlong pointer, we instead in C++ find the _nativeHandle member of the calling Java object, and then directly set the long field from C++.

  1. public class FooByCallInvoke extends NativeBackedObject {
  2. public FooByCallInvoke() {
  3. super();
  4. newFoo(); //the native method, will find _nativeHandle from the class and set it directly
  5. }
  6. private native void newFoo();
  7. ...
复制代码
  1. void Java_com_evolvedbinary_jni_consbench_FooByCallInvoke_newFoo(JNIEnv* env, jobject jobj) {
  2. consbench::Foo* foo = new consbench::Foo();
  3. //set the _nativeHandle in Java
  4. consbench::FooByCallInvokeJni::setHandle(env, jobj, foo);
  5. }
  6. template<class PTR, class DERIVED> class FooJniClass {
  7. public:
  8. // Get the java class id
  9. static jclass getJClass(JNIEnv* env, const char* jclazz_name) {
  10. jclass jclazz = env->FindClass(jclazz_name);
  11. assert(jclazz != nullptr);
  12. return jclazz;
  13. }
  14. // Get the field id of the member variable to store
  15. // the ptr
  16. static jfieldID getHandleFieldID(JNIEnv* env) {
  17. static jfieldID fid = env->GetFieldID(
  18. DERIVED::getJClass(env), "_nativeHandle", "J");
  19. assert(fid != nullptr);
  20. return fid;
  21. }
  22. // Get the pointer from Java
  23. static PTR getHandle(JNIEnv* env, jobject jobj) {
  24. return reinterpret_cast<PTR>(
  25. env->GetLongField(jobj, getHandleFieldID(env)));
  26. }
  27. // Pass the pointer to the java side.
  28. static void setHandle(JNIEnv* env, jobject jdb, PTR ptr) {
  29. env->SetLongField(
  30. jdb, getHandleFieldID(env),
  31. reinterpret_cast<jlong>(ptr));
  32. }
  33. };
  34. // The portal class for com.evolvedbinary.jni.consbench.FooByCallInvoke
  35. class FooByCallInvokeJni : public FooJniClass<consbench::Foo*, FooByCallInvokeJni> {
  36. public:
  37. static jclass getJClass(JNIEnv* env) {
  38. return FooJniClass::getJClass(env,
  39. "com/evolvedbinary/jni/consbench/FooByCallInvoke");
  40. }
  41. };
复制代码
Results

Test machine: MacBook Pro Retina Mid-2015: 2.8 GHz Intel Core i7 / 16 GB 1600 MHz DDR3.

  1. $ java -version
  2. java version "1.8.0_51"
  3. Java(TM) SE Runtime Environment (build 1.8.0_51-b16)
  4. Java HotSpot(TM) 64-Bit Server VM (build 25.51-b03, mixed mode)
复制代码

The com.evolvedbinary.jni.consbench.Benchmark class already calls each scenario 1,000,000 times, so for the benchmark we repeated this 100 times and plotted the results.

Conclusion

Scenario 2 - By Call, Static, appears to have the lowest JNI overhead for constructing C++ objects from Java.

Reproducing

If you want to run the code yourself, you need to have Java 8, Maven 3, and a C++ compiler that supports the C++ 11 standard. You can then simply run:

  1. $ mvn clean compile package
复制代码

In the target/ sub-directory, you will then find both a jni-construction-benchmark-1.0-SNAPSHOT-application folder and a jni-construction-benchmark-1.0-SNAPSHOT-application.zip file, you can use either of these. They both contain bash scripts in their bin/ sub-folders for Mac, Linux, Unix and batch scripts for Windows.

来自: https://github.com/adamretter/jni-construction-benchmark

最新评论

小黑屋|在路上 ( 蜀ICP备15035742号-1 

;

GMT+8, 2025-7-9 00:44

Copyright 2015-2025 djqfx

返回顶部