结论
- 如果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(jniWrapper
AlgInterface
)
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();
}
}

1152

被折叠的 条评论
为什么被折叠?



