Подписывайтесь на наш Telegram и не пропускайте важные новости! Перейти

Гайд Вкатываемся в Java 25 (Panama FFM)

20 iq Slipknot enjoyer, i use arch, btw
Пользователь
Пользователь
Статус
Оффлайн
Регистрация
20 Фев 2025
Сообщения
86
Реакции
37

Предпосылки​


К началу 2010-х годов Java Native Interface (JNI), созданный ещё в 1997 году, накопил множество критических недостатков:


Производительность. Каждый вызов нативной функции через JNI требовал создания JNI-фрейма, перехода между Java и нативным кодом с переключением контекста, маршалинга данных между типами Java и C. Это создавало значительные накладные расходы — вызов простой нативной функции мог быть в 10-100 раз медленнее прямого вызова.


Сложность разработки. Для интеграции с нативной библиотекой требовалось писать промежуточный нативный слой, вручную маршалить все типы данных, управлять локальными и глобальными ссылками на Java-объекты, обрабатывать исключения в обоих направлениях.


Проблемы со сборщиком мусора. Нативный код мог держать ссылки на Java-объекты, что усложняло работу GC. Необходимо было вручную управлять локальными и глобальными ссылками, что часто приводило к ошибкам.

К 2014 году стало ясно, что JNI сдерживает развитие Java в областях, требующих интенсивного взаимодействия с нативными библиотеками — машинное обучение, обработка данных, высокопроизводительные вычисления.


История развития​


Project Panama был запущен в 2014 году и прошёл через несколько ключевых этапов:


2014-2019: Исследования и прототипы. Разработка концепции Foreign Function Interface и Vector API. Первые эксперименты показали возможность достижения производительности, близкой к прямым нативным вызовам.


2019-2021: Foreign Memory Access API. Появился API для безопасной работы с off-heap памятью. Прошёл через несколько итераций в статусе инкубатора (JEP 370, 383, 393), постепенно стабилизируясь.


2021-2022: Объединение в FFM API. В Java 17-19 Foreign Memory Access API объединился с Foreign Linker API в единый Foreign Function & Memory API. Переход в статус preview означал приближение к финальной версии.


2023-2024: Финализация. В Java 22 (март 2024) FFM API стал финальной фичей через JEP 454. API стабилизировался и готов к использованию в продакшене без preview флага.



Архитектура Panama FFM​


MemorySegment — работа с нативной памятью. Представляет непрерывный участок памяти (on-heap, off-heap или mapped). В отличие от прямого доступа через указатели в JNI, MemorySegment предоставляет безопасный типизированный доступ с проверками границ. Поддерживает как примитивные типы, так и сложные структуры данных.


Arena — управление временем жизни памяти. Контролирует жизненный цикл MemorySegment через явные области видимости. Автоматически освобождает всю связанную память при закрытии арены, предотвращая утечки. Поддерживает несколько режимов: автоматический (с GC), confined (привязка к потоку), shared (многопоточный доступ).


SegmentAllocator — аллокация памяти. Предоставляет различные стратегии выделения памяти: разовая аллокация, arena-based allocation, stack-like allocation. Позволяет эффективно работать с временными данными без накладных расходов на GC.


Linker — вызов нативных функций. Создаёт MethodHandle для нативных функций без написания JNI-кода. Автоматически генерирует оптимизированные адаптеры для маршалинга данных. JIT-компилятор может инлайнить такие вызовы, достигая производительности близкой к прямым нативным вызовам.


FunctionDescriptor — описание сигнатур функций. Декларативно описывает типы параметров и возвращаемого значения нативной функции. Использует ValueLayout для точного указания размеров и выравнивания типов. Поддерживает передачу структур по значению, variadic функции и соглашения о вызовах.


SymbolLookup — поиск символов в библиотеках. Загружает нативные библиотеки и находит экспортируемые функции. Поддерживает поиск в системных библиотеках через Linker.nativeLinker().defaultLookup(). Позволяет работать с символами без явной загрузки библиотек через System.loadLibrary.


Все компоненты работают совместно, обеспечивая безопасность через compile-time и runtime проверки, производительность через оптимизации JIT-компилятора, и удобство через декларативный API.



Примеры использования​


Рассмотрим практический пример работы с Panama FFM API.

Вызов стандартной функции strlen из libc:
Expand Collapse Copy
import java.lang.foreign.Arena;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.Linker;
import java.lang.foreign.ValueLayout;
import java.nio.charset.StandardCharsets;

public class StrlenExample {
    public static void main(String[] args) throws Throwable {
        final var linker = Linker.nativeLinker();
        final var stdlib = linker.defaultLookup();
        final var strlenAddr = stdlib.find("strlen").orElseThrow();
        final var strlenDescriptor = FunctionDescriptor.of(
            ValueLayout.JAVA_LONG,  // size_t
            ValueLayout.ADDRESS     // const char*
        );
        final var strlen = linker.downcallHandle(
            strlenAddr,
            strlenDescriptor
        );
        try (final var arena = Arena.ofConfined()) {
            final var str = arena.allocateFrom("Hello World!", StandardCharsets.UTF_8);
            final var length = (long) strlen.invoke(str);
            System.out.printf("Length: %d", length);
        }
    }
}



Сравнение с JNI​


Производительность


Бенчмарки показывают, что Panama FFM опережает JNI — около 50 наносекунд против 57 наносекунд у JNI в тестах на вызов нативных функций
Пожалуйста, авторизуйтесь для просмотра ссылки.
. В ранних версиях Panama (2019 год) производительность уступала JNI, но после переработки API в JDK 15-19, FFM API превзошёл JNI
Пожалуйста, авторизуйтесь для просмотра ссылки.
.


Альтернативные решения показали худшие результаты: JNA — 4037 нс, JNR — 401 нс, BridJ — 1088 нс.


Удобство разработки


JNI требует написания нативного кода, генерации заголовочных файлов, ручного маршалинга данных и компиляции для каждой платформы. Panama FFM работает полностью на Java с декларативным описанием сигнатур и автоматической генерацией биндингов через jextract. Объём работы сократился на 90% по сравнению с JNI
Пожалуйста, авторизуйтесь для просмотра ссылки.
.



Заключение​


С финализацией FFM API в Java 22 появилась современная замена JNI, превосходящая её по производительности и удобству.


Детальные результаты бенчмарков:
Пожалуйста, авторизуйтесь для просмотра ссылки.

Пожалуйста, авторизуйтесь для просмотра ссылки.
 

Предпосылки​


К началу 2010-х годов Java Native Interface (JNI), созданный ещё в 1997 году, накопил множество критических недостатков:


Производительность. Каждый вызов нативной функции через JNI требовал создания JNI-фрейма, перехода между Java и нативным кодом с переключением контекста, маршалинга данных между типами Java и C. Это создавало значительные накладные расходы — вызов простой нативной функции мог быть в 10-100 раз медленнее прямого вызова.


Сложность разработки. Для интеграции с нативной библиотекой требовалось писать промежуточный нативный слой, вручную маршалить все типы данных, управлять локальными и глобальными ссылками на Java-объекты, обрабатывать исключения в обоих направлениях.


Проблемы со сборщиком мусора. Нативный код мог держать ссылки на Java-объекты, что усложняло работу GC. Необходимо было вручную управлять локальными и глобальными ссылками, что часто приводило к ошибкам.

К 2014 году стало ясно, что JNI сдерживает развитие Java в областях, требующих интенсивного взаимодействия с нативными библиотеками — машинное обучение, обработка данных, высокопроизводительные вычисления.


История развития​


Project Panama был запущен в 2014 году и прошёл через несколько ключевых этапов:


2014-2019: Исследования и прототипы. Разработка концепции Foreign Function Interface и Vector API. Первые эксперименты показали возможность достижения производительности, близкой к прямым нативным вызовам.


2019-2021: Foreign Memory Access API. Появился API для безопасной работы с off-heap памятью. Прошёл через несколько итераций в статусе инкубатора (JEP 370, 383, 393), постепенно стабилизируясь.


2021-2022: Объединение в FFM API. В Java 17-19 Foreign Memory Access API объединился с Foreign Linker API в единый Foreign Function & Memory API. Переход в статус preview означал приближение к финальной версии.


2023-2024: Финализация. В Java 22 (март 2024) FFM API стал финальной фичей через JEP 454. API стабилизировался и готов к использованию в продакшене без preview флага.



Архитектура Panama FFM​


MemorySegment — работа с нативной памятью. Представляет непрерывный участок памяти (on-heap, off-heap или mapped). В отличие от прямого доступа через указатели в JNI, MemorySegment предоставляет безопасный типизированный доступ с проверками границ. Поддерживает как примитивные типы, так и сложные структуры данных.


Arena — управление временем жизни памяти. Контролирует жизненный цикл MemorySegment через явные области видимости. Автоматически освобождает всю связанную память при закрытии арены, предотвращая утечки. Поддерживает несколько режимов: автоматический (с GC), confined (привязка к потоку), shared (многопоточный доступ).


SegmentAllocator — аллокация памяти. Предоставляет различные стратегии выделения памяти: разовая аллокация, arena-based allocation, stack-like allocation. Позволяет эффективно работать с временными данными без накладных расходов на GC.


Linker — вызов нативных функций. Создаёт MethodHandle для нативных функций без написания JNI-кода. Автоматически генерирует оптимизированные адаптеры для маршалинга данных. JIT-компилятор может инлайнить такие вызовы, достигая производительности близкой к прямым нативным вызовам.


FunctionDescriptor — описание сигнатур функций. Декларативно описывает типы параметров и возвращаемого значения нативной функции. Использует ValueLayout для точного указания размеров и выравнивания типов. Поддерживает передачу структур по значению, variadic функции и соглашения о вызовах.


SymbolLookup — поиск символов в библиотеках. Загружает нативные библиотеки и находит экспортируемые функции. Поддерживает поиск в системных библиотеках через Linker.nativeLinker().defaultLookup(). Позволяет работать с символами без явной загрузки библиотек через System.loadLibrary.


Все компоненты работают совместно, обеспечивая безопасность через compile-time и runtime проверки, производительность через оптимизации JIT-компилятора, и удобство через декларативный API.



Примеры использования​


Рассмотрим практический пример работы с Panama FFM API.

Вызов стандартной функции strlen из libc:
Expand Collapse Copy
import java.lang.foreign.Arena;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.Linker;
import java.lang.foreign.ValueLayout;
import java.nio.charset.StandardCharsets;

public class StrlenExample {
    public static void main(String[] args) throws Throwable {
        final var linker = Linker.nativeLinker();
        final var stdlib = linker.defaultLookup();
        final var strlenAddr = stdlib.find("strlen").orElseThrow();
        final var strlenDescriptor = FunctionDescriptor.of(
            ValueLayout.JAVA_LONG,  // size_t
            ValueLayout.ADDRESS     // const char*
        );
        final var strlen = linker.downcallHandle(
            strlenAddr,
            strlenDescriptor
        );
        try (final var arena = Arena.ofConfined()) {
            final var str = arena.allocateFrom("Hello World!", StandardCharsets.UTF_8);
            final var length = (long) strlen.invoke(str);
            System.out.printf("Length: %d", length);
        }
    }
}



Сравнение с JNI​


Производительность


Бенчмарки показывают, что Panama FFM опережает JNI — около 50 наносекунд против 57 наносекунд у JNI в тестах на вызов нативных функций
Пожалуйста, авторизуйтесь для просмотра ссылки.
. В ранних версиях Panama (2019 год) производительность уступала JNI, но после переработки API в JDK 15-19, FFM API превзошёл JNI
Пожалуйста, авторизуйтесь для просмотра ссылки.
.


Альтернативные решения показали худшие результаты: JNA — 4037 нс, JNR — 401 нс, BridJ — 1088 нс.


Удобство разработки


JNI требует написания нативного кода, генерации заголовочных файлов, ручного маршалинга данных и компиляции для каждой платформы. Panama FFM работает полностью на Java с декларативным описанием сигнатур и автоматической генерацией биндингов через jextract. Объём работы сократился на 90% по сравнению с JNI
Пожалуйста, авторизуйтесь для просмотра ссылки.
.



Заключение​


С финализацией FFM API в Java 22 появилась современная замена JNI, превосходящая её по производительности и удобству.


Детальные результаты бенчмарков:
Пожалуйста, авторизуйтесь для просмотра ссылки.

Пожалуйста, авторизуйтесь для просмотра ссылки.
знаешь я вот вроде верю что это ты написал, но почему именно длинные тире?
 
знаешь я вот вроде верю что это ты написал, но почему именно длинные тире?
У меня на Клаве этот символ отвалился, из инета первый попавшийся utf код скопировал.
 
Пожалуйста, авторизуйтесь для просмотра ссылки.
Вот гитхаб, когда ссылку вставлял клава залагала походу, щас уже не отредачить
 
Назад
Сверху Снизу