调用流程
在 Java 中使用jna调用 Go 的大致过程如下
java -> jna -> c -> cgo -> go
整个过程要解决的问题主要两个
- 数据类型在两种语言中如何转化
- 内存的释放
示例代码
以下是简单的示例,并解决了内存泄露的问题
Go代码
//export add
func add(a, b ) {
aGo := int(a)
bGo := int(b)
res := aGo + bGo
return (res)
}
//export hello
func hello(name *) * {
data := (name)
cs := ("Hello " + data + "!")
return cs
}
//export freePoint
func freePoint(cs *) {
((cs))
}
func main() {}
Go代码编译为共享库
windows环境编译
使用windows 10的操作系统,gcc使用TDM-GCC-64
windows 64bit 共享库
go build -buildmode=c-shared -o ../resources/win32-x86-64/
windows 32bit 共享库
set CGO_ENABLED=1
set GOARCH=386
go build -buildmode=c-shared -o ../resources/win32-i686/
linux x86 环境编译
使用ubuntu操作系统
linux 64bit 共享库
GOARCH=amd64 GOOS=linux CGO_ENABLED=1 go build -buildmode=c-shared -o ../resources/linux-x86-64/
linux arm64 环境编译
使用ubuntu操作系统
交叉编译器:gcc-8-aarch64-linux-gnu
linux 64bit 共享库
CC=aarch64-linux-gnu-gcc-8 GOARCH=arm64 GOOS=linux CGO_ENABLED=1 go build -buildmode=c-shared -o ../resources/linux-aarch64/
JNA的动态库加载方式
将go打包生成的dll、so或dylib放在java的resources 下的{OS}-{ARCH}/{LIBRARY} 目录内
resources/
|── linux-aarch64
| └──
├── linux-x86-64
│ └──
├── win32-x86-64
│ └──
├── win32-i686
│ └──
├── darwin
│ └──
JAVA代码
在中引入jna
<dependency>
<groupId></groupId>
<artifactId>jna</artifactId>
<version>5.6.0</version>
</dependency>
共享库接口定义
public interface AuthLibrary extends Library {
AuthLibrary INSTANCE = ("awesome", );
int add(int a, int b);
Pointer hello(Pointer name);
void freePoint(Pointer pointer);
}
接口封装
public class AuthServer {
public static String hello(String name) {
// 申请jna的内存空间
Pointer p = new Memory((StandardCharsets.UTF_8).length + 1);
// 设置传入参数值
(0, name);
Pointer ptr = null;
try {
ptr = (p);
return (0, "utf8");
} finally {
// 释放传入jna的指针对应的内存空间
((p));
// 解决多次调用崩溃的问题
(p, 0);
if (ptr != null) {
// 释放go中申请的C的内存
(ptr);
}
}
}
private static void freeJna(Pointer pointer) {
// 释放传入jna的指针对应的内存空间
((pointer));
// 解决多次调用崩溃的问题
(pointer, 0);
}
}
测试代码
public class JNATest {
public static void main(String[] args) {
((1, 2));
int count = 1;
for (int i = 0; i < count; i++) {
String msg = "测试 java -> go,java -> go,java -> go,java -> go,java -> go,java -> go,java -> go,java -> go";
((msg));
}
count = 999999999;
}
测试结果
- 在x86的windows、linux及arm架构的linux均可正常使用
- 在测试代码中将count数量设得很大时,观察到内存使用在200M左右,很稳定,无明显的内存泄露
参考链接
- /blog/2020/08/08/go-meet-java/