结论
- 如果JAVA要高效调用C++函数,则需要通过JNI封装C++函数后进行native方法调用,JNI的执行效率比JNA高600倍左右。
- 从开发效率上来说,JNA开发速度比JNI快许多,因为不需要做二次封装
测试对比
纯C++调用:
Function call took 6700 ns => 0.0067ms
JAVA JNI调用:
Time taken to get version: 515801 ns => 0.515ms
JAVA JNA调用:
Time taken to get version: 333768699 ns => 333.76786ms
原生C++调用验证
1.Visual Studio配置头文件及lib库文件的路径
2.添加附加依赖库
3.调用函数计算时长
#include <iostream>
#include <chrono>
#include <iomanip>
#include "AlgInterface.h"
using namespace std::chrono;int main()
{high_resolution_clock::time_point start = high_resolution_clock::now();int version[4] = { 0 };GetAlgVersion(version);// 结束时间点high_resolution_clock::time_point end = high_resolution_clock::now();// 计算耗时std::chrono::nanoseconds duration = end - start;// 打印结果和耗时std::cout << "Function call took " << duration.count() << "ns\n";std::string versionStr = std::to_string(version[0]) + "." + std::to_string(version[1]) + "." + std::to_string(version[2]) + "." + std::to_string(version[3]);std::cout << versionStr << "\n";return 0;
}
JAVA JNI调用
1.定义JNI方法
public class EcgJniLib {public static native String getVersion(int[] version);
}
2.生成.h头文件,用于包装C++方法
可以简单写个BAT在需要生成JNI的同级目录
> javac D:\WorkSpace\jni\EcgJniLib.java
> javac -h D:\WorkSpace\jni\ D:\WorkSpace\jni\EcgJniLib.java
此时会生成.h文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_cloud_ecgstats_jni_EcgJniLib */#ifndef _Included_com_cloud_ecgstats_jni_EcgJniLib
#define _Included_com_cloud_ecgstats_jni_EcgJniLib
#ifdef __cplusplus
extern "C" {
#endif
/** Class: com_cloud_ecgstats_jni_EcgJniLib* Method: getVersion* Signature: ([I)Ljava/lang/String;*/
JNIEXPORT jstring JNICALL Java_com_cloud_ecgstats_jni_EcgJniLib_getVersion(JNIEnv *, jclass, jintArray);#ifdef __cplusplus
}
#endif
#endif
3.通过Clion封装C++函数
创建动态库
拷贝.h文件,并创建cpp文件
配置cmakelist文件
cmake_minimum_required(VERSION 3.17)
project(jniWrapper)set(CMAKE_CXX_STANDARD 11)#定义头文件需要寻址的路径
include_directories("C:\\EcgAlgo""D:\\Library\\jdk-11.0.15\\include""D:\\Library\\jdk-11.0.15\\include\\win32"
)
#定义库文件需要寻址的路径
link_directories("C:\\EcgAlgo"
)add_library(jniWrapper SHARED library.cpp com_cloud_ecgstats_jni_EcgJniLib.cpp)
target_link_libraries(jniWrapperAlgInterface
)
4.封装执行函数
#include <AlgInterface.h>
#include "com_cloud_ecgstats_jni_EcgJniLib.h"JNIEXPORT jstring JNICALL Java_com_cloud_ecgstats_jni_EcgJniLib_getVersion(JNIEnv* env, jclass, jintArray)
{int version[4];GetAlgVersion(version);std::string versionStr;versionStr = std::to_string(version[0]) + "." + std::to_string(version[1]) + "." + std::to_string(version[2]) + "." + std::to_string(version[3]);jstring jstr = env->NewStringUTF(versionStr.c_str());return jstr;
}
5.构建项目,会生成DLL
6.将生成的DLL及依赖的算法DLL复制到jdk/bin目录下
7.java调用JNI函数执行DLL方法
package com.cloud.ecgstats.jni;import org.springframework.util.StopWatch;public class EcgJniLibInstance {static {System.loadLibrary("jniWrapper");}public static void main(String[] args) {System.out.println(System.getProperty("java.library.path"));StopWatch stopWatch = new StopWatch();stopWatch.start();int[] status = new int[4];String version = EcgJniLib.getVersion(status);stopWatch.stop();System.out.println("Time taken to get version: " + (stopWatch.getTotalTimeNanos()) + "ns");System.out.println(version);}
}
JAVA JNA调用
1.构建DLL Library
package com.cloud.ecgstats.jna;import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;public interface EcgLibrary extends Library {EcgLibrary INSTANCE = Native.load(Platform.isWindows() ? "C:\\AlgInterface.dll" : "/usr/lib/libG.so", EcgLibrary.class);void GetAlgVersion(int[] data);
}
2.调用
package com.cloud.ecgstats.jna;import org.springframework.util.StopWatch;import java.util.Arrays;public class EcgLibraryInstance {public void getVersion(){int[] status = new int[4];StopWatch stopWatch = new StopWatch();stopWatch.start();EcgLibrary.INSTANCE.GetAlgVersion(status);stopWatch.stop();System.out.println("Time taken to get version: " + (stopWatch.getTotalTimeNanos() ) + "ns");System.out.println(Arrays.toString(status));}public static void main(String[] args) {EcgLibraryInstance ecgLibraryInstance = new EcgLibraryInstance();ecgLibraryInstance.getVersion();}
}