bigywater.tech
Java · 306

JNI 与 Panama:两种 native 边界的取舍

JNI 和 Panama 哪个调用更快?传数组时怎么传?MethodHandle 放在哪里会影响多少?这篇用同一个 C 函数、同一个循环,把两条路径量出来(只是本机的一次观察,不是严格基准)。

3.73 vs 4.51 ns
JNI 与 Panama(static final 句柄)的 add 调用耗时
6.69 → 4.51 ns
同一个 Panama 调用,句柄从局部变量改成 static final 之后
87442 vs 11476 ns
262144 个 int 的求和:JNI 复制数组与 GetPrimitiveArrayCritical

JNI 对 Panama 的开销

实测 · 本机执行输出
  第 1 次运行:
    1 add(long, long) 每次调用(ns):Java 方法 0.38;JNI 3.74;Panama(局部变量里的 MethodHandle)6.69;Panama(static final MethodHandle)4.50;Panama static final + critical(false) 3.64
    2 求和 int[16](ns/次):JNI GetIntArrayElements 56;JNI GetPrimitiveArrayCritical 38;JNI DirectByteBuffer 25;Panama(static final 句柄)堆外 MemorySegment 7;Panama critical(true) 直接传堆上的 int[] 5;纯 Java 循环 6
    2 求和 int[1024](ns/次):JNI GetIntArrayElements 394;JNI GetPrimitiveArrayCritical 74;JNI DirectByteBuffer 50;Panama(static final 句柄)堆外 MemorySegment 35;Panama critical(true) 直接传堆上的 int[] 38;纯 Java 循环 105
    2 求和 int[262144](ns/次):JNI GetIntArrayElements 87123;JNI GetPrimitiveArrayCritical 11523;JNI DirectByteBuffer 11399;Panama(static final 句柄)堆外 MemorySegment 11428;Panama critical(true) 直接传堆上的 int[] 11471;纯 Java 循环 37693
  第 2 次运行:
    1 add(long, long) 每次调用(ns):Java 方法 0.35;JNI 3.73;Panama(局部变量里的 MethodHandle)6.69;Panama(static final MethodHandle)4.51;Panama static final + critical(false) 3.59
    2 求和 int[16](ns/次):JNI GetIntArrayElements 57;JNI GetPrimitiveArrayCritical 38;JNI DirectByteBuffer 25;Panama(static final 句柄)堆外 MemorySegment 7;Panama critical(true) 直接传堆上的 int[] 5;纯 Java 循环 6
    2 求和 int[1024](ns/次):JNI GetIntArrayElements 398;JNI GetPrimitiveArrayCritical 75;JNI DirectByteBuffer 50;Panama(static final 句柄)堆外 MemorySegment 36;Panama critical(true) 直接传堆上的 int[] 39;纯 Java 循环 105
    2 求和 int[262144](ns/次):JNI GetIntArrayElements 87442;JNI GetPrimitiveArrayCritical 11476;JNI DirectByteBuffer 11398;Panama(static final 句柄)堆外 MemorySegment 11372;Panama critical(true) 直接传堆上的 int[] 11419;纯 Java 循环 37436

分步演示

JNI 与 Panama
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 27,macOS arm64(10 核),自写计时循环(不是 JMH),每个数字取 5 轮中位数,两次运行一致
    • 没有验证:JMH 严格基准、不同 JIT 状态下的差别、x86 与 Linux、JNI 的 critical 锁对 GC 的停顿影响、带对象参数 / 回调的 JNI 调用开销、JNI 与 Panama 的开发成本(代码量、出错模式)的客观对比
    京ICP备2026067502号-1京公网安备11010502063487号