`

СПЕЦІАЛЬНІ
ПАРТНЕРИ
ПРОЕКТУ

Чи використовує ваша компанія ChatGPT в роботі?

BEST CIO

Определение наиболее профессиональных ИТ-управленцев, лидеров и экспертов в своих отраслях

Человек года

Кто внес наибольший вклад в развитие украинского ИТ-рынка.

Продукт года

Награды «Продукт года» еженедельника «Компьютерное обозрение» за наиболее выдающиеся ИТ-товары

 

Кросс-платформенность и исполняемые файлы

Статья опубликована в №12 (580) от 27 марта

0 
 

Одна из характерных черт Java, во многом обусловившая популярность данного языка, - кросс-платформенность. Как известно, файлы классов могут выполняться в разных операционных средах и на компьютерах различной архитектуры без перекомпиляции. Однако за все приходится платить. В этом случае платой является существенное снижение быстродействия по сравнению с компилируемыми языками.

Компилируем "на ходу"

О том, что интерпретируемые языки отличаются малой скоростью выполнения программного кода, знают все, но не все согласны мириться с этим. Первым шагом на пути повышения производительности Java-программ стала разработка JIT-компилятора (Just-In-Time compiler). Такой подход известен давно, он применялся еще в интерпретаторах Smalltalk и некоторых версиях Lisp. В Java байтовый код, хранящийся в файле класса, преобразуется в машинные команды текущей платформы и запускается на выполнение.

Казалось бы, все в порядке, быстродействие максимально, так как приложение все-таки преобразовано в машинный код, при этом JIT-компилятор точно знает тип процессора, на котором происходит исполнение, и, следовательно, способен оптимизировать код с учетом конкретных особенностей архитектуры. (При обычной компиляции подобная оптимизация невозможна, так как исполняемый файл, полученный на одной машине, обычно предназначается для выполнения на других.) Однако не следует торопиться с оптимистическими выводами. Для выполнения оперативной компиляции нужно время, оно отсчитывается с момента запуска приложения и, следовательно, учитывается при определении производительности программы. И требуется его немало, в особенности если при этом производится оптимизация кода. Может случиться даже так, что выигрыш в быстродействии за счет JIT-компиляции окажется менее существенным, чем потери времени на саму компиляцию. Напрашивается решение: компилировать не все фрагменты кода, а лишь содержащие циклы и другие языковые конструкции, интерпретация которых выполняется неэффективно. Но выявление частей программы, где компиляция была бы целесообразна, опять же дело не одной минуты. В общем, главной задачей оперативного компилятора в составе виртуальной машины Java становится поиск оптимального режима, в котором, с одной стороны код, а, с другой, компиляция не выполнялись бы очень долго.

Java и C: симбиоз возможен

По мере развития языка Java не только создавались новые библиотеки и совершенствовались синтаксические конструкции. Изменялся также круг решаемых задач. Первоначально разработчики Java планировали использовать его для программирования мобильных аппаратов, однако впоследствии выяснилось, что он как нельзя лучше подходит для написания программ, выполняющихся в среде Web. А уже через пять лет Java стал полноценным языком общего назначения, пригодным для создания самых разнообразных приложений, в том числе корпоративных. Для ряда приложений кросс-платформенность оказалась как нельзя кстати, но были и другие, предъявляющие к языку программирования и иные требования. Например, во многих программах нужно организовать управление устройствами, часто нестандартными, т. е. решить задачу, для которой Java уж никак не был предназначен. Действительно, непосредственный доступ к аппаратным средствам прямо противоречит условиям кросс-платформенности. Если язык позволяет обращаться к аппаратным портам, то вряд ли стоит ожидать, что написанная на нем программа будет без перекомпиляции выполняться на компьютерах с разными архитектурами.

Проблема не нова и решение давно найдено: использовать для обработки информации один язык, а управление устройствами осуществлять с помощью модулей, написанных на другом. Для работы с аппаратными средствами во многих случаях прекрасно подходят C и С++, исполняемые файлы которых ориентированы на конкретную платформу. Оказывается, вполне возможно организовать их взаимодействие с платформенно-независимым языком Java. Чтобы программистам было удобнее решать данную задачу, в их распоряжение предоставлен специальный инструмент - Java Native Interface, или JNI.

Благодаря наличию стандартного интерфейса организовать вызов платформенно-ориентированных методов из программы на Java несложно. Для этого надо объявить их с помощью ключевого слова native, предусмотреть в исходном коде Java вызов System.loadLibrary(), и сформировать посредством утилиты javah файл заголовков. После этого можно привычным способом создать динамическую библиотеку (dll), функции которой будут доступны из программы, написанной на Java. JNI не только предоставляет механизм доступа к платформенно-ориентированным функциям, но и отображает типы Java в типы данных языка С (как известно, они различаются между собой).

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

Нельзя не обратить внимание еще на одну важную особенность JNI. Данный инструмент предусматривает также вызов методов Java из платформенно-ориентированной программы. Более того, в ее состав можно даже включить виртуальную машину Java и оформить ее в виде обычного исполняемого файла. В этом случае существенно упрощается процесс доставки приложения. Кроме этого, для неквалифицированного пользователя, навыки которого не выходят за пределы щелчков по кнопкам, вызов интерпретатора Java превратится в непосильную задачу. И тогда программа в виде файла .exe окажется как нельзя более кстати.

И все таки .exe

Переносимость на уровне файлов классов - огромное преимущество Java перед многими другими языками. Однако в некоторых случаях эта возможность остается невостребованной. Действительно, Java-программа вполне способна "прижиться" на компьютере определенной архитектуры, и если пользователи не планируют перехода на другие платформы, то выходит, что плата за переносимость (снижение быстродействия) пропала впустую. А нельзя ли в этом случае повысить производительность, каким-то образом отказавшись от кросс-платформенности? Причем желательно не за счет применения JNI, ведь переписывать исходный код никто не собирается. Почему бы не обработать исходный текст Java AOT-компилятором (Ahead-Of-Time compiler), который, в отличие от JIT-компилятора, преобразовал бы Javа-программу в машинный код не на этапе исполнения, а заранее? Эта мысль приходила в голову многим, и результаты не замедлили проявиться.

За двадцать лет своего существования продукт gcc прошел путь от обычного C-компилятора до пакета, включающего компиляторы с самых различных языков программирования. (Даже расшифровка аббревиатуры gcc за это время изменилась с GNU C Compiler на GNU Compiler Collection.) И, конечно же, в списке поддерживаемых языков не мог не появиться Java. Если обычный Java-компилятор генерирует байтовый код, то gcc (доступный также через отдельную точку входа gcj) предоставляет более широкие возможности. Он позволяет создавать не только файлы классов, включающие байтовый код, но и исполняемые - для текущей платформы, причем при их работе виртуальная машина не используется - программа непосредственно преобразуется в машинный код. А в качестве входных данных компилятору можно задавать как исходный текст Java, так и файлы классов.

Таким образом, работающие с системой UNIX могут при желании избежать накладных расходов, связанных с интерпретацией байтового кода, пожертвовав ради этого переносимостью программы. С Windows дело обстоит несколько хуже. Для нее также существует версия gcc, но выполняться она может только в среде Cygwin. Кроме того, при попытке скомпилировать Java-файл часто возникают проблемы. Отчаявшись решить их, пользователь отправляется искать другие инструменты.

Альтернативный продукт - Excelsior JET, система, позволяющая создавать на базе исходного кода Java исполняемые файлы для операционных систем Windows и Linux. Excelsior JET распространяется на коммерческой основе, причем, по мнению большинства заинтересовавшихся данным продуктом, цена его непомерно высока. Однако ознакомиться с предлагаемыми возможностями можно посредством оценочной версии, для которой определен срок действия в один месяц. В этом случае время от времени будет отображаться окно, напоминающее о том, что система еще не приобретена (вполне естественная защитная мера производителей). ПО требует для работы достаточно много дискового пространства, причем своеобразно реагирует на его нехватку. В частности, на компьютер с 400 MB свободного дискового пространства (уже инсталлированный продукт занимает чуть более 200 MB) оценочную версию Excelsior JET пришлось переустанавливать трижды и каждый раз она вела себя по-разному. Конечно, не исключено, что ее платные реализации (Enterprise, Professional и Standard) работают безукоризненно, но после первого знакомства пользователь, вероятнее всего, по достоинству оценит преимущества решений, созданных в рамках проекта GNU. Попытки же найти компилятор, который генерировал бы исполняемые файлы, идеально работал, да еще и распространялся бесплатно, ни к чему не приведут. Систем подобного назначения, кроме описанных выше, попросту нет.

Если бы да кабы...

Как бы ответственно ни подходили создатели AOT-компиляторов c языка Java к стоящей перед ними задаче, понятно, что их продукты не смогут поддерживать новейшие языковые средства. Независимые производители будут как минимум на шаг отставать от компании Sun Microsystems. Вот если бы платформенно-ориентированный компилятор входил в состав JDK... Ведь создать еще одну утилиту, генерирующую машинный код, разработчикам javac совсем несложно, существенная часть работы - синтаксический разбор исходного кода - уже сделана. Впрочем, наивно думать, что подобная мысль не приходила в голову специалистам Sun Microsystems, и очевидно, что они ее отвергли. В конце концов кросс-платформенность является веским (если не главным) преимуществом Java и любые решения, нивелирующие его, не имеют права на существование. Таким образом, в стремлении повысить быстродействие Java-приложений программистам придется полагаться на JIT-компилятор, либо применить средства JNI для выноса фрагментов кода, критичных к времени выполнения, за пределы Java-программы, либо пользоваться AOT-компиляторами, заранее смирившись с отсутствием поддержки средств, предусмотренных в последней версии языка.

Ready, set, buy! Посібник для початківців - як придбати Copilot для Microsoft 365

0 
 

Напечатать Отправить другу

Читайте также

 

Ukraine

 

  •  Home  •  Ринок  •  IТ-директор  •  CloudComputing  •  Hard  •  Soft  •  Мережі  •  Безпека  •  Наука  •  IoT