Статья опубликована в рамках: XCIX Международной научно-практической конференции «Научное сообщество студентов XXI столетия. ТЕХНИЧЕСКИЕ НАУКИ» (Россия, г. Новосибирск, 11 марта 2021 г.)
Наука: Информационные технологии
Скачать книгу(-и): Сборник статей конференции
дипломов
ПАКЕТ JAVA NATIVE INTERFACE И ОПАСНОСТИ ПРИ РАБОТЕ С НИМ
АННОТАЦИЯ
Иногда Java-разработчикам требуется производить действия за пределами возможностей, предоставляемых данным языком, именно для того существует пакет Java Native Interface, позволяющая интегрировать Java с другими языками. В данной статье будут рассмотрен данный пакет, а также проблемы, с которыми сталкиваются разработчики при его использовании.
Ключевые слова: Java, Java Native Interface, API, C, C++, исключения Java.
JNI или Java Native Interface – API в составе стандартной библиотеки Java, работающий как мост для работы с дополнительными пакетами в рамках среды Java при программировании на языках, отличных от самой Java. Данный пакет используется для преодоления ограничений, установленных платформой Java, а также для интеграции почти любого языка программирования с Java. JNI известен своими ключевыми возможностями:
- Реализацией функций, отсутствующих в стандартных библиотеках. Например, вам может потребоваться функция протокола межсетевых управляющих сообщений (ICMP), при реализации команды «ping» на языке Java, но стандартные библиотеки такой возможности не предоставляют.
- Интеграцией с кодом, который, например, эффективнее выполняется на C или C++, чем на Java, а также ради использования других инструментов, эффективность которых зависит от среды исполнения.
- Особые обстоятельства, требующие кода, отличного от Java. Например, при необходимости обхода ограничений безопасности «java.security».
Java Native Interface позволяет выполнять эти задачи. Он обеспечивает чёткое разделение между выполнением кода Java и нативным кодом (например, C или C ++), определяя чёткий API для связи между ними. С JNI нативный код может свободно взаимодействовать с объектами Java, то есть получать и устанавливать значения полей, а также вызывать методы без каких-либо ограничений, которые применяются к тем же методам в коде Java, также JNI в приложении обеспечивает мощный низкоуровневый доступ к машинным ресурсам (память, механизмы ввода-вывода и т.д.). Эта относительная свобода – палка о двух концах, так как происходит обмен инструментов безопасности языка Java на способность выполнять перечисленные выше задачи. Гибкость и мощность JNI создают риск использования методов программирования, которые могут привести к снижению производительности, ошибкам и даже сбоям программы. Именно поэтому при работе с нативным кодом нужно быть очень острожным, дабы не нарушить общую целостность программы.
1. Использование неправильного JNIEnv
Поток, выполняющий нативный код, использует объект типа JNIEnv для обращений к вызвавшей данный нативный блок среде JNI. Но JNIEnv используется не только для отправки запросов. В спецификации API указано, что каждый JNIEnv является локальным для выполняющего его потока. Виртуальная машина Java полагается на это, сохраняя дополнительную локальную информацию о текущем потоке в JNIEnv. Использование JNIEnv из одного потока другим потоком может привести к незаметным ошибкам и сбоям, которые очень трудно отладить, поэтому используйте JNIEnv только с тем потоком, с которым он связан.
2. Отсутствие проверок на исключения в нативном коде
Многие методы JNI, которые могут вызываться из нативного кода, могут выбрасывать исключения в основном потоке. Когда код Java выполняется, эти исключения вызывают изменение в основном потоке, таким образом что основной поток попадает в блок обработки исключений автоматически. Таким образом, когда нативный компонент вызовет метод JNI, может возникнуть исключение, которое он сам должен обработать. Распространенная ошибка программирования в рамках JNI – это вызвать нативного метода с продолжением работы без проверки исключений после того, как нативный метод завершил свою работу. Это может привести к ошибкам в коде и сбоям.
3. Отсутствие проверки возвращаемого типа
Многие методы JNI имеют возвращаемое значение, которое указывает, был ли вызов успешным или нет. Распространенная ошибка, подобная отсутствию проверки на исключения, это невозможность проверить возвращаемое значение и выполнение нативного метода, предполагая, что вызов был успешным. Для большинства методов JNI следует создавать проверки как на возвращаемое значение, так и статус исключения, которые позволят приложению узнать, работает ли метод правильно.
4. Неправильное использование глобальных ссылок на объекты
Нативные методы могут создавать глобальные ссылки таким образом, что результирующие объекты не обрабатываются сборщиком мусора Java. Распространенная ошибка – это отсутствие удаления данных глобальных ссылок из памяти. Когда глобальная ссылка создается, JVM добавляет её в список, исключающий этот объект из доступных для сборщика мусора. Когда нативный метод возвращает значение, он не только не освобождает глобальную ссылку, но и отнимает у приложения в основном потоке доступ на её получение, потому данный объект будет существовать вплоть до завершения работы программы. Отсутствие чистки глобальных ссылок вызывает проблемы не только потому, что они держат сам объект в памяти, но также потому, что все объекты, к которым данный объект имеет ссылки также держатся в памяти. В некоторых случаях это может привести к значительным утечкам в памяти.
Список литературы:
- Java Native Interface Introduction // Oracle – электронный ресурс, URL: https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/intro.html#java_native_interface_overview (дата обращения: 13.02.2021)
- JNI: подружим Java и C++ // Хабр – электронный ресурс, URL: https://habr.com/ru/post/353294/ (дата обращения: 13.02.2021)
- JNI Types and Data Structures // Oracle – электронный ресурс, URL: https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html (дата обращения: 13.02.2021)
дипломов
Оставить комментарий