用deep-learning-4j在Spring项目中集成深度学习模块的时候,目录中出现了一个.so动态链接库文件,我猜到这也许就是所谓的深度学习Backend,用于使用GPU加速计算,于是便对Java中调用本地程序的过程产生了兴趣,想写个Demo来验证以下。
环境:Linux
以一个Fibonacci数列为例,我们想让他作为native方法存在,而不是用Java实现。定义一个Fibonacci
类,声明两个方法:public class Fibonacci {
public native static void init();
public native static int get(int i);
}
本地方法需要native
关键字修饰,且无方法体。init()
用于初始化一个Fibonacci表,get(i)
用于返回序列某个值。用javah Fibonacci
生成一个Fibonacci.h
头文件:
/* DO NOT EDIT THIS FILE - it is machine generated */ |
头文件中包含了上述两个本地方法的声明,第一个参数是JNIEnv*
类型,由于Java中是静态方法,第二个参数是jClass
类型,之后的参数对应是Java方法的参数列表。接着只需要实现他们即可,创建Fibonacci.cpp
,在其中对上述两个方法写实现。
// Fibonacci.cpp |
接着将本地程序编译成动态链接库即可。编译动态链接库需要用到jni.h
和jni_md.h
,其中jni.h
位于$JAVA_HOME/include/jni.h
,而jni_md.h
在Linux下位于$JAVA_HOME/include/linux/jni_md.h
,在Windows下位于$JAVA_HOME/include/win32
。将他们拷贝到当前路径下,修改头文件中的#include <jni.h>
为#include "jni.h"
,然后编译即可。cp $JAVA_HOME/include/jni.h .
cp $JAVA_HOME/include/linux/jni_md.h . #$JAVA_HOME/include/win32 if windows
g++ -shared -fPIC Fibonacci.cpp -o libfibonacci.so
编译生成动态链接库libfibonacci.so
,只需要将他加载进内存,就可以调用绑定他的native方法了。可以用System.loadLibrary("fibonacci")
加载fibonacci
库,也可以用System.load("/xxx/xxxx/libfibonacci.so")
指定.so
文件的绝对路径。一般加载过程写在绑定他的类的静态代码块中,在类加载的时候加载。动态链接库的加载可以写在任何地方,加载一次即可。
public class Fibonacci { |
需要注意的是,
System.loadLibrary
的加载方式必须把库的位置添加到环境变量java.library.path
中
最后在调用Fibonacci
提供的本地方法测试:public class Main {
public static void main(String[] args) {
Fibonacci.init();
for(int i = 0; i < 10; i++) {
System.out.println(Fibonacci.get(i));
}
}
}
输出正常:1
1
2
3
5
8
13
21
34
55
更多详细JNI样例见:Java JNI进阶编程