探机之家
探机的自我修养

Introductory Use of JNI


What is JNI?

Java Native Interface, often abbreviated as JNI, allows Java code running in the JVM to call C/C++ or assembly code. JNI enables C code to create or use Java objects to run performance-sensitive code more efficiently, and also allows bypassing Java’s memory management system to use memory more effectively. Many Java bindings for machine learning are implemented using JNI.

Below is a simple example to guide you through writing a JNI program. The IDE used in this example is Intellij IDEA.

##Writing a Java Class First, create a Java project (in this example, the project name is hellojni).

public class HelloJNI {
static {
// Load the dynamic link library file
System.loadLibrary("hello");
}
// native indicates a JNI method
private native void sayHello();
public static void main(String[] args) {
new HelloJNI().sayHello();
}
}

Generating the Header File

Click the Build button (or use the first command below), and an out folder will be generated in the project’s root directory.

Then, generate the header file using the following command:

Terminal window
javac HelloJNI.java # if not using IDEA
javah -jni -classpath out/production/jni/ -d jni/include org.cclin.hellojni.HelloJNI

Here, the classpath specifies the class directory, -d specifies the output location, and the class name follows. This will generate a header file named org_cclin_hellojni_HelloJNI.h in jni/include.

/* 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 __cplusplus
extern "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

Next, you need to implement the generated header file.

Configuring CMakeLists.txt and Writing Implementation

cmake_minimum_required(VERSION 3.24)
project(hellojni)
set(CMAKE_CXX_STANDARD 20)
# Find JNI header files and libraries
find_package(JNI REQUIRED)
# The library name should match what is used in `System.loadLibrary("hello")`
add_library(hello SHARED HelloJNI.cpp)
target_include_directories(hello PRIVATE include)
# Add header files
target_include_directories(hello PRIVATE ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2})

Now that we have prepared the CMake configuration, the remaining task is to implement the code in 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;
}

In CLion, click Build to generate the libhello.dylib file in the cmake-build-debug directory (on Linux, it will be libhello.so), or use the command line cmake -B build && cmake --build build.

Adding the Dynamic Library to Java

When running Java, provide the JVM parameter -Djava.library.path to point to the location of the .so file generated in the previous step. In IDEA, you can add the VM option -Djava.library.path=$ContentRoot$/jni/cmake-build-debug.

Once set, you can click Run to execute the program.

(Contents below are untested) In practice, the .so file is often placed in the resources directory, and you can retrieve it using Class.getResource or ClassLoader.getResource. The resource is then stored in a temporary file, and that temporary file is loaded instead of specifying the path explicitly via -Djava.library.path.

https://docs.oracle.com/en/java/javase/11/docs/specs/jni/design.html https://blog.csdn.net/createchance/article/details/53783490