Многозадачная Java: наступление на системном фронте
Арсений Чеботарев.
Компьютеры+Программы
Идея Java OS может стать реальностью уже в ближайшем будущем. Благодаря нескольким новым интерфейсам и изменениям в виртуальной машине, разрабатываемым в рамках проекта Barcelona.
До сих пор Java была изначально отделена от операционной системы с помощью Java Runtime. В результате этот язык программирования обладал многими полезными свойствами — но не теми, которые делали бы его пригодным для системного программирования. В частности, не предусматривалось никаких встроенных средств управления ресурсами. Это препятствовало реализации такой давно вынашиваемой идее, как полностью самостоятельная операционная среда Java OS. Для выполнения системных функций разработчику приходилось пользоваться обычным в таких случаях языком С — и потом возвращаться в код Java. И хотя в Java изначально включена совместимость с C и это взаимодействие давно не вызывает проблем, тем не менее у многих переход в Native Code вызывал ощущение, будто что-то не так, как должно быть. Функции управления заданиями могли б быть реализованы средствами Java — при условии поддержки их со стороны системы времени выполнения.
Вторым мотивом для введения многопоточности стало распространение параллельного выполнения нескольких Java-приложений в нескольких копиях виртуальной машины. При этом виртуальные машины не оптимизировали использование памяти и тактов процессора. В частности, каждая из VM отдельно от остальных разбирала каждый из пакетов, в том числе стандартных,— и таким образом значительная часть работы дублировалась.
В результате для решения поставленных задач и вновь возникающих проблем, связанных с масштабируемостью и надежностью, был создан Barcelona Project. В кратком описании этого проекта явно сформулирована его цель: превратить Java в полноценную операционную среду. Метод: прозрачное разделение метаданных (системных данных) между приложениями.
Первоначально было решено не менять существующую виртуальную машину в корне, но дополнить ее модулем, который, по замыслу, должен отвечать за совместно используемые ресурсы и эффективно кэшировать их. Каждая запускаемая копия виртуальной машины загружала очередную порцию классов в общую область — и таким образом эффект кэширования для каждого следующего экземпляра VM проявлялся все лучше. На следующем этапе были переработаны основные библиотеки, в которых были выделены реентерабельные блоки кода "только для чтения".
Часть данных, составляющая состояние приложения, которая не может быть разделена между приложениями, включает глобальные переменные, которые в терминах Java представлены статическими членами системных и пользовательских классов. Код — как данные только для чтения — по определению поддается повторному использованию, а значения динамических членов не нуждаются в реентерабельности.
Прирост быстродействия и экономии памяти для обоих подходов составил около 10%, однако главная цель не была достигнута, поскольку основное время при запуске приложения составляет запуск самого Java Runtime. То есть, запуская новые виртуальные машины, никогда не удастся достичь желаемой гибкости, особенно для небольших приложений, таких как утилиты командной строки. Поэтому было решено вынести Runtime в категорию (квази-)резидентных в памяти программ (демонов, сервисов) и сделать Java многопоточной и реентерабельной средой для множества приложений. Таким образом, JRE запускается только один раз (возможно — только при запуске компьютера), и накладных расходов типа "CreateProcess" при запуске отдельных приложений, в том числе и первого, не возникает.
На данном этапе существует прототип многопоточной виртуальной машины, MVM, основанной на Hot Spot Virtual Machine и соответствующем компиляторе. Основным принципом построения новой машины, по словам Гжегожа Чайковски (Grzegorz Czaikowski), руководителя проекта Barcelona, стала проверка всех компонент Java VM на предмет разделения функциональности между приложениями. В результате каждая выполняемая программа требует только ограниченных частных ресурсов, связанных с состоянием приложения. Большинство кода и метаданных теперь обслуживают все приложения одновременно. В частности, удалось сделать реентерабельными в рамках многопоточной виртуальной машины стандартные библиотеки классов, которые используют все без исключения приложения.
В результате скорость запуска приложений возросла на 60…90% — и для большинства приложений, в том числе и графических, составляет теперь около одной секунды. Стало возможным даже реализовать такие системные утилиты, как ls или grep,— раньше этому препятствовало значительное время запуска, которое сводило на нет преимущества эффективности таких команд. Оперативная память, занимаемая приложением, сократилась в полтора-два раза за счет повторного использования стандартных модулей. Когда одно приложение требует модуль, то он уже, как правило, загружен и находится в кэше виртуальной машины.
Наблюдается также рост производительности самих приложений. Причина — выполнение всех приложений в одном процессе, в результате чего переключение между приложениями не вызывает системного переключения контекста. Например, приложение баз данных (реализованное на 100% Java) и сервер приложений, работающие в одном процессе MVM, показали 11-процентный прирост пропускной способности обмена данными и на 36% лучшее время реакции на запросы.
Безусловно, объединяя приложения в одной виртуальной машине, необходимо обеспечить их "гальваническую развязку", то есть гарантировать неприкосновенность их адресных пространств. В MVM роль такого защитного контейнера выполняет изолятор — экземпляр специального типа Isolate. Это контейнер для приложений, позволяющий не только гарантировать частное адресное пространство, но и манипулировать приложением, мониторить его ресурсы и обеспечивать чистое завершение приложения. Класс Isolate является частью Application Isolation API Spec, выдвинутой на форуме Java Community Process (www.jcp.org/en/jsr/detail?id=121).
Что еще важно — менеджер загрузки модулей будет использовать изоляторы прозрачно для существующих приложений, так что они не потребуют модификации. Собственно, изоляция не подразумевает ограничений в плане реализации и может быть представлена как в мультипотоковой виртуальной машине, так и средствами нескольких VM.
Важное следствие из применения изоляторов — те полезные ограничения, которые налагает изоляция на взаимодействие приложений. В частности, изоляция обеспечивает взаимодействие процессов только средствами сокетов, файлов или JRI — то есть теми методами, которые могут быть легко спроектированы на кластерные архитектуры. Фактически, модульное приложение, использующее два и больше изоляторов, будет даже на одном компьютере работать так же, как если бы это было распределенное сетевое окружение.
Еще одним важным системным интерфейсом, служащим для мониторинга ресурсов, обещает стать Resource Management (RM) Interface. Этот основанный на изоляторах механизм позволяет гибко создавать и опрашивать счетчики системных ресурсов — от таких низкоуровневых, как процессорное время, до высокоуровневых, типа подключения к серверу приложений или баз данных. Как и в случае с изоляцией, менеджмент ресурсов легко спроектировать на сетевое окружение.
Новая виртуальная машина не только сможет обслуживать несколько приложений одновременно — вполне возможно также, что эти приложения будут выполняться под различными пользовательскими эккаунтами. В результате JVM приобретает свойства самостоятельной среды выполнения, обладающей средствами для выполнения множества приложений в многопользовательской среде.
Новая MVM была опробована как на мобильных терминалах, где экономия памяти является важнейшей задачей (хотя и отсутствуют жесткие конкурентные условия для приложений), так и на сервере приложений J2EE, который, как правило, и запускался в нескольких экземплярах для обеспечения развязки нескольких приложений. Оба теста показали эффективность MVM, причем без модификации основного кода — путем прозрачного использования изоляторов. Реализация MVM для J2SE остается под вопросом — эта среда не ориентирована на выполнение нескольких приложений или, по крайней мере, не в такой степени, как сервер приложений.
Все это может иметь значительные последствия для применения Java вообще. Если раньше средний пользователь характеризовал приложения Java как "медленные" и "расходующие ресурсы", то теперь эти характеристики уже не будут играть негативной роли. Особенно субъективно важным и значительно улучшенным параметром является время запуска приложения. Для администраторов должна показаться привлекательной возможность управлять многими приложениями и осуществлять аудит ресурсов из одной точки. А программисты к тому же получат выгоды от новых интерфейсов, которые еще больше приближают Java к выполнению решающей роли в мире вычислений.
Ссылки по теме: