FFM API — нативный код и off-heap память без JNI

Тема дорожной карты · Java

Foreign Function & Memory API (FFM) — итог многолетнего Project Panama и штатная замена JNI, финализирован в Java 22 (JEP 454). API решает две задачи: вызов функций нативных библиотек (C ABI) напрямую из Java и безопасная работа с памятью вне кучи. В отличие от JNI не нужно писать «клеевой» код на C и собирать отдельную нативную библиотеку-прослойку — всё описывается на Java, а инструмент jextract генерирует биндинги из готовых заголовочных файлов автоматически.

Как это работает

Три опоры API. Linker связывает Java с ABI платформы и создаёт MethodHandle для downcall (вызов Java → нативная функция) и upcall (обратный вызов из нативного кода в Java-метод). MemorySegment — ограниченное и проверяемое представление области памяти: каждый доступ контролируется по границам и времени жизни. Arena управляет временем жизни выделенной нативной памяти: закрытие арены детерминированно освобождает все её сегменты, без ожидания GC и финализаторов.

static long nativeStrlen(String s) throws Throwable {
    Linker linker = Linker.nativeLinker();
    MethodHandle strlen = linker.downcallHandle(
        linker.defaultLookup().find("strlen").orElseThrow(),
        FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS));
    try (Arena arena = Arena.ofConfined()) {
        MemorySegment cStr = arena.allocateFrom(s);  // копия строки в нативной памяти
        return (long) strlen.invokeExact(cStr);
    }
}

Практический бонус — производительность: создаваемые линкером связки JIT умеет инлайнить и оптимизировать, поэтому downcall на многих замерах обгоняет эквивалентный вызов через JNI, при этом весь связующий код остаётся на стороне Java и проверяется компилятором. Доступ к сегменту после закрытия арены бросает исключение, а не роняет процесс — принципиальное отличие от JNI и sun.misc.Unsafe, где такая ошибка означает segfault или тихую порчу памяти. Вызовы нативных функций относятся к restricted-методам: в свежих версиях JDK модулю нужно явно выдать право флагом --enable-native-access, иначе JVM печатает предупреждение при первом вызове.

Когда применять

Типичные ошибки

Связанные понятия

Полезные ресурсы

Проверить знания (2)

Загрузка вопросов…