Повышение производительности JavaScript в Internet Explorer 10 и Windows 8


В четверг 31 мая 2012 года мы представили Windows 8 Release Preview и шестую версию Internet Explorer 10 Platform Preview. В Windows 8 один обработчик вывода веб-страниц HTML5 обеспечивает работу обоих типов браузера (в стиле Metro и классического), а также приложений в стиле Metro, использующих HTML5 и JavaScript. В Release Preview представлена существенно измененная версия современного обработчика JavaScript, названного Chakra, который впервые появился в Internet Explorer 9. С каждой предварительной версией платформы мы становимся все ближе к цели по созданию обработчика, который обеспечивает высокую производительность при работе в Интернете и предоставляет высокий уровень совместимости, взаимодействия и безопасности. В данной статье рассматриваются улучшения, которые были внесены в обработчик JavaScript для обеспечения высокой производительности в рамках новых сценариев работы веб-приложений.

Производительность для реальных веб-приложений

В течение нескольких последних лет наблюдается быстрое развитие и распространение веб-приложений. Десятилетие назад Интернет по большей части представлял собой веб-сайты со статическим контентом, который можно встретить и сейчас в блоге, на целевой странице сайта малого предприятия или в Википедии. Появление AJAX поспособствовало распространению более сложных и интерактивных сайтов, которые можно увидеть в Facebook или JetSetter. Дальнейшие усовершенствования производительности сделали возможным создание больших и сложных приложений, таких как Office 365, Карты Bing и т. п. Недавнее расширение стандартных API консорциума W3C, меры по увеличению производительности JavaScript и использование графики с аппаратным ускорением позволили реализовать в Интернете самые изысканные игры, такие как Angry Birds, Pirates Love Daisies, Cut The Rope и т. п.

Схема, показывающая спектр веб-страниц и их характеристик производительности. Слева находятся базовые веб-страницы, для которых основным показателем производительности является время загрузки страницы. Справа находятся веб-приложения, игры HTML5 и приложения в стиле Metro Windows 8, в которых наибольшее влияние на производительность оказывают скорость выполнения JavaScript, взаимодействия с моделью DOM и ускорение графики.

По мере развития приложений меняются и факторы, влияющие на изменение взаимодействия с пользователем. Для традиционных веб-сайтов загрузка начальной страницы определяет то, насколько быстро пользователь может просматривать контент. Интерактивные веб-сайты и крупные веб-приложения могут быть чувствительны к эффективности операций модели DOM, обработке CSS и управлению большим внутренним состоянием в памяти. Игры HTML5 часто зависят от быстрой отрисовки полотна, выполнения JavaScript и эффективности сборки мусора. Другими словами, производительность браузера — это многогранная проблема, для решения которой необходимо учесть потребности обширного спектра разнообразных приложений.

В данной статье мы сосредоточим внимание на производительности только одной подсистемы браузера — обработчика JavaScript. Благодаря последним мерам по увеличению производительности JavaScript для многих веб-приложений выполнение JavaScript перестало быть ограничивающим фактором. С другой стороны, по мере увеличения производительности появляются новые сценарии, которые предъявляют к обработчику JavaScript повышенные требования. Мы стремимся постоянно расширять возможности Chakra, чтобы соблюсти требования к производительности, предъявляемые приложениями, которые предполагают действительно интенсивное использование JavaScript.

Двухмерная диаграмма со снимками экранов разных сайтов, расположенными по двум осям: использование других компонентов браузера (ось Y) и выполнение JavaScript (ось X). Сайты контента приведены в нижней левой части (наименьшее использование других компонентов браузера и наименьшее использование JavaScript). Игры с большим объемом графики, такие как Angry Birds, находятся в правом верхнем квадранте.
Измерения производительности веб-приложений

Внутренние задачи Chakra

С момента своего появления в Internet Explorer 9 обработчик JavaScript Chakra разрабатывался в соответствии с двумя главными принципами, которые полностью сохранили свою актуальность и в Internet Explorer 10:

  • Минимизация объема работы, выполняемой на критическом пути для взаимодействия с пользователем. Это включает в себя задержку выполнения как можно большей части работы до тех пор, пока без него уже нельзя будет обойтись, полное прекращение работы, использование периодов неактивности и распараллеливание работы в целях минимизации влияния, которое оказывается на время отклика приложения.
  • Использование преимуществ доступного оборудования. Это означает использование всех доступных ядер ЦП, а также создание расширенных специализированных инструкций ЦП, например SSE2 компании Intel, если они имеются.

Схема, иллюстрирующая использование обработчиком JavaScript Chakra двух ядер процессора.
Параллельная архитектура обработчика Chakra

Однако сам обработчик Chakra представляет собой одну из подсистем браузера и состоит из нескольких компонентов, которые работают совместно для обработки и выполнения кода JavaScript. Когда браузер загружает файл JavaScript, он передает его содержимое в средство синтаксического анализа Chakra для проверки правильности синтаксиса. Это единственная операция, которая применяется к файлу в целом. Последующие операции выполняются по отдельности для каждой из функций (включая глобальную). Когда функция готова к выполнению (глобальная функция запускается сразу же после синтаксического разбора), средство синтаксического анализа Chakra создает представление кода в виде дерева абстрактного синтаксиса (AST) и передает его в генератор байт-кода, который создает промежуточную форму (байт-код), предназначенную для выполнения интерпретатором (но не самим ЦП). Как дерево абстрактного синтаксиса, так и байт-код функции сохраняются, поэтому их не требуется создавать повторно при последующих выполнениях. После этого вызывается интерпретатор для выполнения функции. По мере выполнения отдельных операций интерпретатор собирает информацию (профиль) о типах входных данных, которые он обнаруживает, и отслеживает количество вызовов функции.

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

JavaScript — это управляемая среда выполнения, где управление памятью скрыто от разработчика и реализуется автоматическим сборщиком мусора, который периодически запускается для очистки неиспользуемых объектов. В Chakra применяется традиционный, имеющий квазиреализацию поколений и работающий по принципу разметки и очистки, сборщик мусора, который основную часть своей работы выполняет параллельно в выделенном потоке, что позволяет минимизировать паузы в выполнении скрипта, оказывающие отрицательное влияние на взаимодействие с пользователем.

Такая архитектура позволяет Chakra во время загрузки страницы почти сразу же начинать выполнение кода JavaScript. С другой стороны, в периоды интенсивной работы JavaScript Chakra может распараллеливать ее и подключать до трех ядер ЦП, осуществляя выполнение скрипта, компиляцию и сборку мусора одновременно.

Малое время загрузки страницы

Даже относительно статичные веб-сайты часто используют JavaScript для реализации интерактивных возможностей, рекламы или общего доступа к социальным сетям. Фактически объем кода JavaScript, включенного в 1 миллион наиболее популярных страниц по версии Alexa, постоянно увеличивается (по данным HTTP-архива Стива Соудерса (Steve Souders)).

Диаграмма, показывающая объем кода JavaScript в 1 миллионе наиболее популярных страниц по версии Alexa
Объем кода JavaScript в 1 миллионе наиболее популярных страниц по версии Alexa

Включенный в эти веб-сайты код JavaScript должен обрабатываться обработчиком JavaScript браузера, а для полной отрисовки контента должна выполняться глобальная функция каждого файла скрипта. Таким образом, крайне важно минимизировать объем работы, выполняемой на этом критическом пути. Именно данную цель и мы ставили перед собой при разработке средства синтаксического анализа и интерпретатора байт-кода Chakra.

Интерпретатор байт-кода. Код JavaScript, выполняемый во время загрузки страницы, часто осуществляет инициализацию и настройку, которые проводятся только один раз. Чтобы сократить общее время загрузки страницы, необходимо приступить к выполнению этого кода немедленно, не ожидая, пока JIT-компилятор обработает код и выдаст машинные команды. Интерпретатор начинает выполнять код JavaScript, как только он преобразуется в байт-код. Чтобы дополнительно сократить время до первой выполненной инструкции, Chakra обрабатывает и выдает байт-код только для тех функций, которые скоро будут выполнены. Для этого используется механизм под названием отложенный синтаксический разбор.

Отложенный синтаксический разбор.Диаграмма, показывающая часть кода, выполняемую на 11 популярных веб-сайтах. Объем варьируется в диапазоне от чуть более 30 % до чуть более 50 %.Проект JSMeter отдела исследований Майкрософт показал, что типичные веб-страницы используют только часть загружаемого ими кода — обычно около 40–50 % (см. приведенную слева диаграмму). На интуитивном уровне это может показаться разумным: разработчики часто включают в свои продукты популярные библиотеки JavaScript, например, jQuery, dojo или собственные — аналогичные используемым в Office 365, хотя и применяют лишь часть функциональных возможностей, поддерживаемых соответствующей библиотекой.

Чтобы оптимизировать такие сценарии, Chakra осуществляет только самый базовый синтаксический разбор исходного кода. Остальная часть работы (построение дерева абстрактного синтаксиса и создание байт-кода) выполняется для одной функции за раз и только тогда, когда соответствующая функция будет скоро вызвана. Описанная стратегия не только помогает повысить скорость отклика браузера при загрузке веб-страниц, но и сокращает объем используемой памяти.

В Internet Explorer 9 на отложенный синтаксический разбор Chakra накладывалось одно ограничение. Функции, вложенные внутрь других функций, должны были анализироваться немедленно вместе с содержащими их функциями. Это ограничение оказалось оправданным, так как во многих библиотеках JavaScript применяется так называемый «модульный шаблон», когда основная часть кода библиотеки заключается в большую функцию, которая немедленно выполняется. В Internet Explorer 10 мы убрали это ограничение, и теперь Chakra откладывает синтаксический разбор и создание байт-кода для любой функции, которая выполняется не сразу.

Улучшения производительности для приложений, интенсивно использующих JavaScript

Как и в Internet Explorer 9, в Internet Explorer 10 мы стремимся повысить производительность реальных веб-приложений. Однако зависимость веб-приложений от производительности JavaScript не является постоянной величиной. При рассказе об улучшениях в Internet Explorer 10 лучше всего сосредоточиться на приложениях, интенсивно использующих JavaScript, в которых улучшения Chakra позволяют получить существенный прирост производительности. К важному классу таких приложений с интенсивным использованием JavaScript относятся симуляции и игры HTML5.

На начальном этапе разработки Internet Explorer 10 мы анализировали образцы популярных игр JavaScript (например, Angry Birds, Cut the Rope или Tankworld) и симуляции (например, FishIE Tank, HTML5 Fish Bowl, Ball Pool, Particle System), чтобы понять, какие улучшения производительности оказали бы наибольшее влияние на взаимодействие с пользователем. В результате такого анализа было выявлено несколько общих характеристик и закономерностей написания кода. Работа всех этих приложений основана на обратном вызове таймера высокой частоты. Большинство из них используют для отрисовки полотно, однако некоторые приложения полагаются на анимацию элементов модели DOM, в других же используется сочетание этих двух способов. Для большинства приложений код, по крайней мере частично, написан в соответствии с принципами объектно-ориентированного программирования либо в самом приложении, либо в прилагаемых библиотеках (например, Box2d.js). Широко распространены короткие функции, а также операции считывания и записи свойств и полиморфизм. Все такие приложения выполняют арифметические операции с плавающей запятой, а многие из них занимают довольно большой объем памяти, что затрудняет сборку мусора. Именно на таких общих закономерностях мы и сосредоточили внимание при работе над повышением производительности в Internet Explorer 10. В следующих разделах описаны внесенные нами изменения.

Пересмотр и улучшение JIT-компилятора

Internet Explorer 10 включает в себя значительные улучшения JIT-компилятора Chakra. Мы добавили поддержку двух дополнительных архитектур процессоров: x64 и ARM. В результате как на 64-разрядном компьютере, так и на планшетном ПК на базе процессора ARM выполнение приложения JavaScript осуществляется непосредственно на ЦП.

Мы также изменили основополагающий подход к созданию машинного кода. Язык JavaScript является крайне динамичным, в результате чего на момент создания кода в распоряжении компилятора имеются лишь ограниченные данные. Например, при компиляции приведенной ниже функции компилятору неизвестна форма (макет свойств) используемых объектов или типы их свойств.

function compute(v, w) {

return v.x + w.y;

}

В Internet Explorer 9 компилятор Chakra создавал код, который обнаруживал каждое из свойств во время выполнения и обрабатывал все достоверно возможные операции (в приведенном выше примере это сложение целых чисел, сложение чисел с плавающей запятой или даже объединение строк). Некоторые из этих операций обрабатывались непосредственно в машинном коде, для других требовалась среда выполнения Chakra.

JIT-компилятор в Internet Explorer 10 создает машинный код, который основан на профилях и специализирован для конкретных типов. Другими словами, он создает машинный код, который ориентирован на объекты определенной формы и значения определенного типа. Чтобы выдать правильный код, компилятору требуется знать ожидаемые типы входных значений. Поскольку JavaScript — это динамический язык, в исходном коде данная информация отсутствует. Мы улучшили интерпретатор Chakra для сбора таких данных в среде выполнения и назвали эту методику динамическим профилированием. При назначении функции для JIT-компиляции компилятор изучает полученный интерпретатором профиль данных о среде выполнения и выдает код, ориентированный на ожидаемые входные значения.

Интерпретатор собирает данные о наблюдаемых им запусках, однако существует вероятность, что выполнение программы приведет к таким значениям во время выполнения, которые нарушают допущения, сделанные при создании оптимизированного кода. Для каждого принимаемого допущения компилятор выполняет проверку в среде выполнения. Если при последующем выполнении возникает неожиданное значение, проверка завершается со сбоем, выполнение в аварийном режиме выводится из специализированного машинного кода и продолжается в интерпретаторе. Регистрируется причина такого аварийного вывода (неудачная проверка), интерпретатор собирает дополнительные сведения о профиле, после чего выполняется повторная компиляция функции при других допущениях. Аварийная остановка и повторная компиляция представляют собой две абсолютно новые возможности в Internet Explorer 10.

В результате компилятор Chakra в Internet Explorer 10 создает для кода меньше машинных команд, что сокращает общий объем используемой памяти и ускоряет выполнение. Это оказывает особенно сильное влияние на приложения с арифметическими операциями с плавающей запятой и операциями доступа к свойствам объектов, в число которых входят симуляции и игры HTML5.

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

Ускорение арифметических операций с плавающей запятой

Большинство программ JavaScript выполняют некоторое количество арифметических операций с целыми числами. В приведенном ниже примере показано, что даже в тех программах, которые не ориентированы на арифметические операции, целые значения часто используются в качестве переменных итерации для циклов или в качестве индексов в массивах.

function findString(s, a) {

for (var i = 0, al = a.length; i < al; i++) {

if (a[i] == s) return i;

}

return -1;

}

С другой стороны, операции с плавающей запятой обычно характерны лишь для ограниченного круга приложений, таких как игры, симуляции, приложения для работы со звуком, видео или изображениями и т. п. Раньше для создания таких приложений язык JavaScript использовался крайне редко, однако последние улучшения в области производительности браузеров сделали реализацию на JavaScript вполне возможной. В Internet Explorer 9 мы оптимизировали Chakra для выполнения наиболее распространенных операций с целыми числами. В Internet Explorer 10 мы существенно улучшили выполнение математических операций с плавающей запятой.

function compute(a, b, c, d) {

return (a + b) * (c − d);

}

Для приведенной выше несложной функции компилятор JavaScript не может определить типы аргументов a, b, c и d по исходному коду. В этом случае компилятор Internet Explorer 9 предположил бы, что эти аргументы с большой вероятностью будут целыми числами, и создал бы быстродействующие машинные команды для работы с целыми числами. И все было бы хорошо при условии, что во время выполнения эти аргументы действительно оказались бы целыми числами. В случае использования чисел с плавающей запятой коду пришлось бы полагаться на вспомогательные функции в среде выполнения Chakra, обладающие существенно меньшим быстродействием. Дополнительная нагрузка в виде вызовов функций усугублялась упаковкой и распаковкой промежуточных значений в куче (в большинстве 32-разрядных обработчиков JavaScript, включая Chakra, отдельные значения с плавающей точкой должны распределяться из кучи). В приведенном выше выражении результат каждой операции требовал распределения из кучи с последующим сохранением в ней значения и извлечением этого значения из кучи для выполнения следующей операции.

В Internet Explorer 10 компилятор использует преимущества сведений о профиле, собранных интерпретатором, для создания кода, который несравнимо быстрее обрабатывает значения с плавающей запятой. Если в приведенном выше примере профиль указывает на то, что все аргументы с большой вероятностью будут числами с плавающей запятой, компилятор выдает машинные команды для значений с плавающей запятой. Полностью это выражение будет рассчитано всего за три машинные команды (при условии, что все аргументы уже находятся в регистрах), все промежуточные значения будут сохранены в регистрах и для возврата окончательного результата потребуется всего одно распределение из кучи.

Для приложений с большим числом операций с плавающей запятой это обеспечивает потрясающий прирост производительности. Эксперименты показывают, что операции с плавающей запятой в Internet Explorer 10 выполняются примерно на 50 % быстрее, чем в Internet Explorer 9. Кроме того, сокращение объема выделяемой памяти позволяет уменьшить число сборок мусора.

Ускоренный доступ к объектам и свойствам

Объекты JavaScript представляют собой удобный и распространенный механизм группировки логически связанных наборов значений. Независимо от того, используются ли объекты JavaScript в рамках структурированных принципов объектно-ориентированного программирования или просто в качестве гибкого средства упаковки значений, возможности повышения производительности при выделении объектов и доступе к свойствам, которые были добавлены в Internet Explorer 10, окажут заметное положительное влияние на ваш код.

Как уже упоминалось ранее, в JavaScript эффективный доступ к свойствам осложнен тем, что во время компиляции форма объекта неизвестна. Объекты JavaScript можно создавать динамически, по случаю без использования предварительно определенного типа или класса. Новые свойства можно добавлять в объекты (и даже удалять из них) оперативно и в любом порядке. В результате при компиляции следующего метода компилятор не знает, где искать значения для свойств x, y и z объекта Vector.

Vector.prototype.magnitude = function() {

return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);

}

В Internet Explorer 9 мы ввели встроенный кэш, который значительно ускорил доступ к свойствам. Встроенный кэш запоминает форму объекта и расположение в памяти объекта, где можно найти заданное свойство. Встроенный кэш может запомнить только одну форму объекта и является эффективным, когда все объекты, с которыми работает функция, имеют одинаковую форму. В Internet Explorer 10 мы добавили механизм вторичного кэширования, который улучшает производительность кода, работающего с объектами разной формы (полиморфизм).

Перед считыванием значения свойства компилятор должен проверить, что форма объекта соответствует форме, сохраненной во встроенном кэше. Для этого компилятор в Internet Explorer 9 перед каждым доступом к свойству выполняет проверку формы в среде выполнения. Поскольку программы часто считывают или записывают несколько свойств одного объекта подряд (как в приведенном ниже примере), все эти проверки увеличивают дополнительные затраты времени.

function collide(b1, b2) {

var dx = b1.x - b2.x;

var dy = b1.y - b2.y;

var dvx = b1.vx - b2.vx;

var dvy = b1.vy - b2.vy;

var distanceSquare = (dx * dx + dy * dy) || 1.0;

//...

}

Chakra в Internet Explorer 10 создает код, ориентированный на ожидаемую форму объекта. Благодаря тщательному отслеживанию символов в сочетании с возможностями аварийной остановки и повторной компиляции новый компилятор значительно сокращает число проверок формы в среде выполнения. В приведенном выше примере вместо 8 отдельных проверок формы выполняется всего 2 — по одной для b1 и b2. Кроме того, после установки формы объекта все расположения свойств становятся известны, поэтому операции чтения или записи выполняются так же эффективно, как и в C++.

В ECMAScript 5 объекты могут содержать новые виды свойств, которые называются свойствами метода доступа. Свойства метода доступа отличаются от обычных свойств данных вызовом настраиваемых функций get и set для обработки операций чтения и записи. Свойства метода доступа представляют собой удобный механизм для добавления инкапсуляции данных, вычисляемых свойств, проверки данных и уведомлений об изменениях. При разработке системы внутренних типов и встроенного кэша обработчика Chakra была предусмотрена совместимость со свойствами метода доступа и возможность эффективного считывания и записи их значений.

При создании игры или анимации HTML5 вам часто требуется физический модуль, который осуществляет расчеты для реалистичного моделирования столкновений, перемещения объектов под воздействием силы тяжести и т. п. Вы можете построить отдельный модуль для каждого простого физического воздействия, но в более сложных ситуация вы бы предпочли использовать одну из появившихся в JavaScript популярных физических библиотек, таких как Box2d.js (перенесена из Box2d). Эти библиотеки часто используют небольшие объекты, такие как Point, Vector или Color. Для каждого кадра анимации создается и оперативно удаляется множество таких объектов. Следовательно, очень важно, чтобы в среде выполнения JavaScript обеспечивалось эффективное создание объектов.

var Vector = function(x, y, z) {

this.x = x;

this.y = y;

this.z = z;

}

 

Vector.prototype = {

//...

normalize : function() {

var m = Math.sqrt((this.x * this.x) + (this.y * this.y) + (this.z * this.z));

return new Vector(this.x / m, this.y / m, this.z / m);

},

 

add : function(v, w) {

return new Vector(w.x + v.x, w.y + v.y, w.z + v.z);

},

 

cross : function(v, w) {

return new Vector(-v.z * w.y + v.y * w.z, v.z * w.x - v.x * w.z, -v.y * w.x + v.x * w.y);

},

//...

}

В Internet Explorer 10 внутренняя структура объектов JavaScript оптимизирована, что позволяет упростить их создание. В Internet Explorer 9 каждый объект состоял из заголовка фиксированного размера и расширяемого массива свойств. Такой массив необходим для размещения дополнительных свойств, которые могут добавляться уже после создания объекта. Данная удобная возможность используется не всеми приложениями JavaScript, в результате при создании объектов в них часто включается основная часть их свойств. Данная особенность позволяет Chakra выделять основную часть свойств для таких объектов непосредственно с заголовком, поэтому для каждого создаваемого объекта выполняется только одно выделение памяти (вместо двух). Кроме того, это изменение ведет к уменьшению числа сбросов ссылки на память, требуемых для считывания или записи свойства объекта, а также повышает эффективность использования регистров. Улучшенная структура объектов и меньшее число проверок формы в среде выполнения обеспечивают ускорение доступа к свойствам до 50 %.

Улучшения сборки мусора

Как было описано выше, для анимаций и игр HTML5 часто имеет место ситуация, когда объекты создаются и удаляются с высокой частотой. Программы JavaScript не выполняют явное уничтожение удаленных объектов для освобождения памяти. Вместо этого они полагаются на сборщик мусора, который периодически освобождает память, занятую неиспользуемыми объектами, для размещения новых объектов. Автоматическая сборка мусора делает процесс программирования проще, однако во время работы сборщика мусора выполнение JavaScript обычно требуется приостанавливать. Если работа сборщика занимает длительное время, браузер может полностью перестать реагировать на действия пользователя. В играх HTML5 даже кратковременные паузы (длительностью в десятки миллисекунд) создают помехи, так как воспринимаются пользователем как рывки анимации.

В Internet Explorer 10 мы внесли несколько улучшений для процессов выделения памяти и сборки мусора. Мы уже рассмотрели изменения в структуре объектов и создание машинного кода, ориентированного на арифметические операции с плавающей запятой, что позволило сократить объем выделяемой памяти. Кроме того, теперь Chakra выделяет конечные объекты (например, числа и строки) из отдельной области памяти. Конечные объекты не содержат указатели на другие объекты, поэтому им не требуется удалять при сборке мусора столько внимания, сколько обычным объектам. Выделение конечных объектов из отдельной области предоставляет два преимущества. Во-первых, на этапе разметки всю эту область можно пропустить, что сокращает длительность всего этапа. Во-вторых, во время сопутствующей сборки мусора новые выделения из области конечных объектов не требуют повторного сканирования затронутых страниц. Поскольку сборщик Chakra работает одновременно с основным потоком скрипта, выполняющийся скрипт может изменять или создавать объекты на уже обработанных страницах. Чтобы предотвратить преждевременный сбор таких объектов, перед началом этапа разметки Chakra устанавливается для страниц защиту от записи. Страницы, в которые на этапе разметки выполнялась запись, позднее должны пройти повторное сканирование в основном потоке скрипта. Поскольку для конечных объектов такая обработка не требуется, страницы из области конечных объектов не требуется защищать от записи или повторно сканировать позднее. Это позволяет сэкономить ценное время в основном потоке скрипта и сократить паузы. Данное изменение очень выгодно для анимаций и игр HTML5, так как они часто перегружены операциями с плавающей запятой и используют значительную часть выделенной памяти для хранения чисел, упакованных в кучу.

Когда пользователь взаимодействует непосредственно с веб-приложением, крайне важно, чтобы код этого приложения выполнялся как можно быстрее — в идеальном случае перерывы в работе на сборку мусора должны отсутствовать полностью. Однако когда пользователь переключается с браузера на другое приложение или просто переходит на другую вкладку, важно сократить объем памяти, занимаемый неактивными сайтом и приложением. Именно поэтому в Internet Explorer 9 обработчик Chakra активировал сбор для существующего кода JavaScript при наличии достаточного объема выделенной памяти. Для большинства приложений этот способ работал правильно, однако для приложений, работа которых основывалась на таймерах высокой частоты, таких как анимации и игры HTML5, он приводил к возникновению проблем. Для таких приложений сборка мусора активировалась слишком часто, что приводило к снижению частоты кадров и общему ухудшению взаимодействия с пользователем. Возможно, наиболее показательным примером данной проблемы стала игра Tankworld, однако приостановки анимации, вызванные частыми сборками мусора, наблюдались и в других симуляциях HTML5.

В Internet Explorer 10 мы решили данную проблему посредством координирования сборок мусора с работой остальных компонентов браузера. Теперь Chakra откладывает сборку мусора до конца выполнения скрипта, а после периода неактивности скрипта запрашивает из браузера обратный вызов. Если этот период заканчивается до выполнения любого скрипта, Chakra запускает сборку мусора, в противном случае сборка опять откладывается. Данная методика позволяет сократить объем используемой памяти, когда браузер неактивен (или неактивна одна из его вкладок), а также существенно уменьшить частоту сборок мусора в приложениях с большим количеством анимации.

Вместе эти изменения позволили в среднем до четырех раз (в протестированных симуляциях HTML5) сократить время, затрачиваемое на сборку мусора в основном потоке. Процентное отношение времени сборки мусора ко времени выполнения JavaScript сократилось с 27 % до 6 %.

Заключение

Internet Explorer 10 обеспечивает существенный прирост производительности для приложений с интенсивным использованием JavaScript, в частности игр и симуляций HTML5. Такой прирост стал возможен благодаря внесению ряда важных улучшений в обработчик Chakra: начиная с новых основополагающих возможностей JIT-компилятора и вплоть до изменений в сборщике мусора.

Завершая разработку Internet Explorer 10, мы с удовлетворением констатируем, что в этой области нами достигнут значительный прогресс. Вместе с тем мы прекрасно понимаем, что поиск возможностей для повышения производительности является бесконечным процессом. Практически ежедневно появляются новые приложения, которые подвергают возможности современных браузеров и их обработчиков JavaScript серьезному испытанию. Не сомневаюсь, что в следующем выпуске нам еще предстоит активная работа в данном направлении!

Если вы разрабатываете приложения на JavaScript, нам было бы интересно услышать ваши отзывы. Если новые возможности и повышение производительности в Internet Explorer 10 помогли вам создать совершено новые методы взаимодействия с пользователем или каким-либо образом улучшить свои приложения, обязательно сообщите нам знать о своих достижениях. Дайте нам знать и в том случае, если вы натолкнулись на какие-либо ограничения производительности в Internet Explorer. Мы внимательно изучаем все комментарии к данному блогу и стремимся сделать Internet Explorer 10 и Windows 8 самой совершенной и производительной платформой приложений.

— Эндрю Миадович (Andrew Miadowicz), руководитель программы, JavaScript

Skip to main content