CodeWalk

JNI与JNA对比:Native方法调用的选择

作者:屠龙少年 · 2026-05-30 12:55

请对比**JNI(Java Native Interface)JNA(Java Native Access)**的异同。它们各自的实现原理是什么?JNI的性能更高但开发复杂度也更高,JNA的易用性更好但性能有损失,如何在实际项目中选择?什么是JaNa(Java Native Access)的Library和Function映射?

回答

屠龙少年

JNI(Java Native Interface)

原理:Java调用C/C++的动态链接库(.so/.dll),通过javah生成头文件,手动编写C代码实现方法。

// Java端
public class NativeLib {
    static { System.loadLibrary("native"); }
    public native int add(int a, int b);
}
// C端(自动生成头文件后实现)
JNIEXPORT jint JNICALL Java_NativeLib_add(JNIEnv *env, jobject obj, jint a, jint b) {
    return a + b;
}

优点:性能最高(几乎无封装开销),完全控制Native代码。 缺点:开发复杂(需生成头文件、处理类型映射、管理引用)、跨平台编译麻烦、JNI函数调用开销。

JNA(Java Native Access)

原理:运行时动态解析Native函数,通过反射调用。无需编写C代码,只需Java接口定义。

// JNA接口定义
public interface NativeLib extends Library {
    NativeLib INSTANCE = Native.load("native", NativeLib.class);
    int add(int a, int b);  // 自动映射到C函数
}

// 使用
int result = NativeLib.INSTANCE.add(1, 2);

优点:开发简单(纯Java,无C/C++代码)、自动类型映射、跨平台友好。 缺点:性能略低于JNI(函数调用经过JNA桥接层)、启动时需加载和解析。

性能对比

维度JNIJNA
调用开销~4-8 ns~30-100 ns
启动时间极短稍长(库加载+解析)
类型映射手动,最优自动,有开销
性能损耗几乎无~10x于JNI

选择建议

  • JNI:高频调用的热点代码(游戏引擎、音视频编解码、高频交易)
  • JNA:低频调用、快速原型、已有C库需快速集成
  • Java 22+ Foreign Function & Memory API(Project Panama):未来最佳方案,比JNI更安全、性能接近JNI、无C代码编写

Unsafe类

sun.misc.Unsafe(JDK9+标记为废弃):

  • 直接操作堆外内存(allocateMemory/putLong/getLong)
  • CAS操作(compareAndSwapObject)
  • 绕过构造方法创建对象(allocateInstance)
  • 线程park/unpark

风险:JVM崩溃、内存泄漏、不可移植。推荐替代:Java 22+ Foreign Memory API / VarHandle / Atomic类。