JNI初步使用
JNI 是什么
Java Native Interface, 通常缩写为 JNI,。它可以使得在JVM中运行的 Java 代码能够调用 C/C++ 或者汇编所编写的代码。JNI 可以让 C 代码创建或者使用 Java 对象,来更加高效的运行一些性能敏感型代码,也可以绕过 Java 的内存管理机制来更加高效的使用内存。很多机器学习的 Java binding 都是通过 JNI 实现的。
下边举一个简单的例子来带大家写一个 JNI 程序。所用 IDE 是 Intellij IDEA。
编写 Java class
首先创建 Java 工程,步骤略(例子中项目名为 hellojni)
package org.cclin.hellojni;
public class HelloJNI { static { //加载的 动态链接库 的文件名 System.loadLibrary("hello"); }
//native 表示 jni 的方法 private native void sayHello();
public static void main(String[] args) { new HelloJNI().sayHello(); }}
生成头文件
点击编译按钮(或者使用下边第一条命令),会在项目根目录生成 out 文件夹
随后用以下命令生成头文件
javac HelloJNI.java # 如果不使用IDEAjavah -jni -classpath out/production/jni/ -d jni/include org.cclin.hellojni.HelloJNI
其中 classpath 指定类目录,-d 指定输出位置,后面是类名
此时会在 jni/include
中生成名为 org_cclin_hellojni_HelloJNI.h
的头文件
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class org_cclin_hellojni_HelloJNI */
#ifndef _Included_org_cclin_hellojni_HelloJNI#define _Included_org_cclin_hellojni_HelloJNI#ifdef __cplusplusextern "C" {#endif/* * Class: org_cclin_hellojni_HelloJNI * Method: sayHello * Signature: ()V */JNIEXPORT void JNICALL Java_org_cclin_hellojni_HelloJNI_sayHello (JNIEnv *, jobject);
#ifdef __cplusplus}#endif#endif
接下来需要为这个生成的头文件编写对应的实现
配置 CmakeLists.txt 并编写实现
cmake_minimum_required(VERSION 3.24)project(hellojni)
set(CMAKE_CXX_STANDARD 20)
# 查找 JNI 的头文件库find_package(JNI REQUIRED)
# library 名字应与 `System.loadLibrary("hello")` 中的相同add_library(hello SHARED HelloJNI.cpp)target_include_directories(hello PRIVATE include)# 添加头文件target_include_directories(hello PRIVATE ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2})
这样我们便准备好了 cmake,剩下的只需要在 HelloJNI.cpp 中编写实现就够了
#include <iostream>#include "org_cclin_hellojni_HelloJNI.h"
JNIEXPORT void JNICALL Java_org_cclin_hellojni_HelloJNI_sayHello (JNIEnv *, jobject) { std::cout << "HelloJNI" << std::endl;}
在 CLION 中点击编译即可在 cmake-build-debug
中看到 libhello.dylib
文件(Linux 下为 libhello.so
)
或者使用命令行cmake -B build && cmake --build build
为 java 添加动态链接库
在运行 java 时提供 JVM 参数 -Djava.library.path
指向上一步的 .so
文件位置
可以在 IDEA 中添加 VM options -Djava.library.path=$ContentRoot$/jni/cmake-build-debug
设置完成后点击运行即可
(以下内容未经测试)
在实际使用中,.so 文件会被放入到 resource 目录下,
通过 Class.getResource 或者 ClassLoader.getResource 获取资源,
存储到临时文件中,再加载该临时文件,而不用通过 Djava.library.path
显示指定路径
https://docs.oracle.com/en/java/javase/11/docs/specs/jni/design.html https://blog.csdn.net/createchance/article/details/53783490