← [ BACK_TO_NOTES ]

JNI 概览

JNI 如何让 Java 调用本地代码:适用场景、安全与可移植性代价。

#concept #growing #dev #java

[!info] related notes

JNI 概览

这个概念为什么出现

极少数场景必须调用 OS API、硬件 SDK 或既有 C/C++ 库。JNI 是经典互操作桥,但破坏 WORA 的“无本地假设”,并引入崩溃与内存风险。

[!abstract] 一句话理解 JNI 通过 native 方法把调用转到本地库;用可移植性与安全边界换取本地能力,应评估本地边界,并在需要进程故障隔离时采用进程外方案。

最小可观察示例

场景:声明 native 方法(不链接真实库,仅展示形态)

public class NativeTime {
    public native long monotonicNanos();
    public static void main(String[] args) {
        System.out.println("jni-boundary-demo");
    }
}
javac -h headers NativeTime.java && java NativeTime

期望:

jni-boundary-demo

此命令还生成 headers/NativeTime.h;main 未调用 native 方法,所以无需真实库。若直接调用未绑定的 monotonicNanos,会抛 UnsatisfiedLinkError。真实调用还需 C/C++ 实现、相匹配的本地二进制及加载/注册步骤。

结合场景再看三个关注点

  1. 本地崩溃可拖垮 JVM 进程。
  2. 每平台交付本地 .so/.dll/.dylib。
  3. 优先查是否有纯 Java 或 FFM 新方案。

核心概念与准确模型

1. 边界

Java 声明 native 方法,本地实现可按 JNI 命名规则导出符号,也可用 RegisterNatives 显式注册。System.loadLibrary 接收逻辑库名(如 native_time),由运行时按平台规则寻找;System.load 接收本地库绝对路径。

2. 引用与临界区

JNI 引用不是可长期保存的裸对象地址。局部引用与全局引用有不同生命周期,全局引用需 DeleteGlobalRef 释放;JNIEnv 属于当前线程,不能跨线程共享。获取数组/字符串数据后需配对释放,并遵守相应临界区限制,不能用一句“防 GC 移动”替代这些规则。

3. 替代

  • 进程外 sidecar
  • Foreign Function & Memory API:JEP 454 在 JDK 22 正式交付;JDK 21 的版本仍是 preview。它提供另一条互操作路径,不自动消除本地代码导致的进程崩溃。

边界情况与反直觉行为

  1. 难以调试的 mixed stack。
  2. 容器镜像架构(amd64/arm64)必须匹配。
  3. 库缺失、CPU/ABI 不匹配、依赖库缺失都可能导致加载失败。另需按目标 JDK 核对 native access 策略:JEP 472 在 JDK 24 默认对未授权的 JNI native access 发出警告,可按模块配置 --enable-native-access;不要把历史 SecurityManager 策略当作新 JDK 的统一模型。

常见误区

[!warning] 常见误区:为了“更快”先写 JNI 多数热点应先算法与分配,再测;JNI 调用本身也有成本。

工程实践

  1. 本地代码最小化表层。
  2. 严格 CI 多架构。
  3. 崩溃处理与可观测。
  4. 文档写清非纯 Java 依赖。

本节总结

  • JNI=本地桥
  • 可移植性与安全代价高
  • 最后手段

自测题

  1. JNI 如何影响 WORA?
  2. 为何容器要多架构构建本地库?
参考答案
  1. 引入平台相关二进制,不再“只发 jar 即可到处跑”。
  2. CPU 架构不同,本地指令与 ABI 不通用。

延伸阅读与资料来源

资料类型支撑内容
JNI Specification规范JNI
FFM APIJEPJDK 22 正式交付
Prepare to Restrict the Use of JNIJEPJDK 24 native access 策略
创建于 2026/7/15 更新于 2026/10/6
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本