JEP 178: Statically-Linked JNI Libraries
статически скомпонованные библиотеки JNI
| Ответственный | Bob Vandette |
| Тип | Feature |
| Область | SE |
| Статус | Closed / Delivered |
| Выпуск | 8 |
| Компонент | core-libs |
| Обсуждение | jdk8 dash dev at openjdk dot java dot net |
| Трудоёмкость | S |
| Длительность | S |
| Рецензенты | Alan Bateman, Alex Buckley |
| Одобрен | Mark Reinhold |
| Создан | 2013/02/18 20:00 |
| Обновлён | 2016/06/07 16:40 |
| Задача | 8046168 |
Аннотация
Расширить спецификацию JNI, чтобы она поддерживала статически скомпонованные нативные библиотеки.
Цели
-
Изменить спецификацию Java SE и JDK так, чтобы разработчики могли упаковать среду выполнения Java, нативный код приложения и Java-код приложения в один исполняемый двоичный файл, которому не нужны разделяемые нативные библиотеки.
-
Не требовать изменений в существующем Java-коде, чтобы использовать статическую нативную библиотеку вместо динамической. В частности, вызов метода вида
System.loadLibrary("foo")должен загружать библиотеку"foo"независимо от того, предоставлена ли она в статической или в динамической форме. -
Позволить Java-приложению использовать сочетание статических и динамических нативных библиотек, при этом статические библиотеки должны находиться в памяти до любой попытки их использовать.
-
Позволить при необходимости статически компоновать Java-агенты JVMTI со средами выполнения Java.
Что не является целью
Сохранение полной совместимости нативного исходного кода на C/C++ для существующих динамических нативных библиотек, переведённых в статическую форму, не является целью. Существующие использования функций JNI_OnLoad и JNI_OnUnLoad придётся изменить, чтобы несколько статических библиотек могли сосуществовать.
Мотивация
Есть два основных сценария, в которых статические библиотеки JNI могут быть полезны:
-
Нативным приложениям, встраивающим JRE, может потребоваться статически скомпонованный код JNI вместо динамически компонуемых библиотек.
-
Java-приложениям, работающим в средах, которые ограничивают разделяемые библиотеки или не поддерживают их, нужно, чтобы JRE и весь код её нативных библиотек API были скомпонованы в один исполняемый файл.
Дополнительное преимущество: со статически скомпонованными библиотеками JNI компоновщик объектных файлов может оптимизировать весь исполняемый файл и, возможно, уменьшить его размер.
Описание
Чтобы добавить поддержку статических библиотек JNI, нужно решить две основные проблемы:
-
Текущий Java API, который запускает процесс загрузки динамической библиотеки, нужно расширить для поддержки встроенных статических библиотек. Java-приложению, использующему статическую библиотеку JNI, нужен способ сообщить VM, что код библиотеки уже включён в образ приложения. В этом случае запрос
System.loadLibraryдля статической библиотеки должен пропускать обычный платформенно-зависимый процесс динамической загрузки.Текущая спецификация JNI упоминает такую поддержку, но VM HotSpot такое поведение не реализует.
-
Интерфейс функций
JNI_OnLoadиJNI_OnUnloadнужно расширить для поддержки имён, специфичных для библиотеки, поскольку в приложении может существовать только одна функция с данным именем. Это можно реализовать, добавляя имя библиотеки к этим общеизвестным именам. Например,libnet.soможет использоватьJNI_OnLoad_net,JNI_OnUnload_net.
Эта возможность требует изменений как в API загрузки библиотек Java SE, так и в спецификации JNI. Ниже приведён первоначальный черновик изменений спецификации в обеих областях.
Изменения в Java API
Спецификации методов java.lang.System.load и java.lang.Runtime.load будут изменены так:
Загружает нативную библиотеку, указанную аргументом filename. Аргумент filename должен быть абсолютным путём.
Если аргумент filename после удаления платформенно-зависимого префикса библиотеки, пути и расширения файла указывает на библиотеку с именем L и нативная библиотека с именем L
statically linkedс VM, то вместо попытки загрузить динамическую библиотеку вызывается экспортируемая библиотекой функция JNI_OnLoad_L. Файл, соответствующий аргументу, не обязан существовать в файловой системе. Подробности см. в спецификации JNI.В противном случае аргумент filename отображается на образ нативной библиотеки способом, зависящим от реализации.
Спецификации того, когда эти методы выбрасывают UnsatisfiedLinkError, будут изменены так:
UnsatisfiedLinkError— если filename не является абсолютным путём, нативная библиотека неstatically linkedс VM или хост-система не может отобразить библиотеку на образ нативной библиотеки.
Спецификации методов java.lang.System.loadLibrary и java.lang.Runtime.loadLibrary будут изменены так:
Загружает нативную библиотеку, указанную аргументом
libname.libnameне должен содержать платформенно-зависимого префикса, расширения файла или пути.Если нативная библиотека с именем
libnamestatically linkedс VM, то вызывается экспортируемая библиотекой функцияJNI_OnLoad_libname. Подробности см. в спецификации JNI.В противном случае
libnameзагружается из системного расположения библиотек и отображается на образ нативной библиотеки способом, зависящим от реализации.
Спецификации того, когда эти методы выбрасывают UnsatisfiedLinkError, будут изменены так:
UnsatisfiedLinkError— если аргумент libname содержит путь к файлу, нативная библиотека неstatically linkedс VM или хост-система не может отобразить библиотеку на образ нативной библиотеки.
Изменения в спецификации JNI
-
Нативная библиотека может быть
statically linkedс VM. Способ объединения библиотеки и образа VM зависит от реализации. -
Чтобы эта библиотека считалась загруженной, вызов
System.loadLibraryили эквивалентного API должен завершиться успешно. -
Библиотека L, образ которой объединён с VM, считается
statically linkedтогда и только тогда, когда библиотека экспортирует функцию с именем JNI_OnLoad_L. -
Если
statically linkedбиблиотека L экспортирует функцию с именемJNI_OnLoad_Lи функцию с именемJNI_OnLoad, функцияJNI_OnLoadбудет проигнорирована. -
Если библиотека L
statically linked, то при первом вызовеSystem.loadLibrary("L")или эквивалентного метода будет вызвана функцияJNI_OnLoad_Lс теми же аргументами и ожидаемым возвращаемым значением, что указаны для функцииJNI_OnLoad. -
Если библиотека L
statically linked, то динамически компоновать библиотеку с тем же именем будет запрещено. -
Когда загрузчик классов, содержащий
statically linkedнативную библиотеку L, удаляется сборщиком мусора, VM вызовет функциюJNI_OnUnload_Lэтой библиотеки, если такая функция экспортируется. -
Если
statically linkedбиблиотека L экспортирует функцию с именемJNI_OnUnLoad_Lи функцию с именемJNI_OnUnLoad, функцияJNI_OnUnLoadбудет проигнорирована.
Версия спецификации JNI будет увеличена до JNI_VERSION_1_8. Статически скомпонованные библиотеки будут поддерживаться только в этой или более поздней версии.
Изменения в спецификации параметра командной строки JVMTI -agentlib
Описание параметра командной строки -agentlib в спецификации будет изменено в JDK 8 так:
Если аргумент
libraryуказывает на библиотеку с именем L и нативная библиотека с именем Lstatically linkedс VM, то агент должен экспортировать функциюAgent_OnLoad_L. Библиотека, соответствующая аргументу, не обязана существовать в файловой системе. Эта функцияAgent_OnLoad_Lбудет вызвана VM, как описано в спецификации JVMTI.optionsбудут переданы функцииAgent_OnLoad_Lпри её вызове.В противном случае имя после -agentlib: — это имя загружаемой библиотеки. Поиск библиотеки, как её полного имени, так и расположения, выполняется платформенно-зависимым способом. Обычно
agent-lib-nameпреобразуется в имя файла, специфичное для операционной системы.optionsбудут переданы агенту при запуске. Например, если указан параметр -agentlib:foo=opt1,opt2, VM попытается загрузить разделяемую библиотеку foo.dll из системного PATH в WindowsTM или libfoo.so из LD_LIBRARY_PATH в операционной среде SolarisTM.
Изменения в спецификации параметра командной строки JVMTI -agentpath
Описание параметра командной строки -agentpath в спецификации будет изменено в JDK 8 так:
Если аргумент
filenameпосле удаления платформенно-зависимого префикса библиотеки, пути и расширения файла указывает наlibraryс именем L и нативная библиотека с именем Lstatically linkedс VM, то агент должен экспортировать функциюAgent_OnLoad_L. Файл, соответствующий аргументу, не обязан существовать в файловой системе. Эта функцияAgent_OnLoad_Lвызывается VM, как описано в спецификации JVMTI.optionsбудут переданы функцииAgent_OnLoad_Lпри её вызове.В противном случае путь после -agentpath: — это абсолютный путь, по которому загружается библиотека. Преобразование имени библиотеки не выполняется.
optionsбудут переданы агенту при запуске. Например, если указан параметр -agentpath:/myLibs/foo.so=opt1,opt2, VM попытается загрузить разделяемую библиотеку /myLibs/foo.so.
Изменения в спецификации нативного интерфейса JVMTI
-
Нативный агент JVMTI может быть
statically linkedс VM. Способ объединения библиотеки и образа VM зависит от реализации. -
Агент L, образ которого объединён с VM, считается
statically linkedтогда и только тогда, когда агент экспортирует функцию с именемAgent_OnLoad_L. -
Если
statically linkedагент L экспортирует функцию с именемAgent_OnLoad_Lи функцию с именемAgent_OnLoad, функцияAgent_OnLoadбудет проигнорирована. -
Если агент L
statically linked, будет вызвана функцияAgent_OnLoad_Lс теми же аргументами и ожидаемым возвращаемым значением, что указаны для функцииAgent_OnLoad. -
Если агент L
statically linked, агент с тем же именем нельзя будет загрузить динамически. -
VM вызовет функцию
Agent_OnUnload_Lагента, если такая функция экспортируется, в тот же момент запуска, в который она вызвала бы динамическую точку входаAgent_OnUnLoad. -
Если
statically linkedагент L экспортирует функцию с именемAgent_OnUnLoad_Lи функцию с именемAgent_OnUnLoad, функцияAgent_OnUnLoadбудет проигнорирована. -
Если агент L
statically linked, будет вызвана функцияAgent_OnAttach_Lс теми же аргументами и ожидаемым возвращаемым значением, что указаны для функцииAgent_OnAttach. -
Если
statically linkedагент L экспортирует функцию с именемAgent_OnAttach_Lи функцию с именемAgent_OnAttach, функцияAgent_OnAttachбудет проигнорирована.
com.sun.tools.attach.VirtualMachine.loadAgentLibrary
В javadoc этого метода будет добавлен следующий текст:
Если агент
statically linkedс VM, которая в ином случае загрузила бы его, то имя вызываемой функцииAgent_OnAttachбудет специфичным для библиотеки, как определено в разделе спецификации JVMTI о -agentlib.
com.sun.tools.attach.VirtualMachine.loadAgentPath
В javadoc этого метода будет добавлен следующий текст:
Если агент
statically linkedс VM, которая в ином случае загрузила бы его, то имя вызываемой функцииAgent_OnAttachбудет специфичным для библиотеки, как определено в спецификации JVMTI о -agentpath.
Версия спецификации JVMTI будет увеличена до JDK18_JVMTI_VERSION.
Значением JDK18_JVMTI_VERSION будет 0x30010203, что соответствует версии 1.2.3.
Эта новая функциональность будет поддерживаться в виртуальных машинах, поддерживающих JDK18_JVMTI_VERSION или более позднюю версию.
Влияние
- Совместимость: эта новая функциональность не должна влиять на существующие динамические библиотеки.
- Переносимость: при статической сборке нативного исходного кода JNI требуется изменить имена функций.
- TCK: тесты нативных библиотек JNI нужно будет адаптировать для проверки поддержки статически скомпонованных нативных библиотек.
- TCK: тесты агентов JVMTI нужно будет адаптировать для проверки поддержки статически скомпонованных библиотек агентов.