React Native выпускает JS-движок нового поколения Hermes

React Native
React Native выпускает JS-движок нового поколения Hermes

Не так давно на конференции ChainReact 2019 Facebook официально запустил движок исполнения JavaScript нового поколения Hermes. Hermes — это небольшой и легкий движок JavaScript, оптимизированный для запуска React Native на Android. Для многих приложений простое включение Hermes может улучшить время запуска, использование памяти и размер приложения, а также, поскольку он реализован в стандартах JavaScript, его легко интегрировать в приложения React Native.

在这里插入图片描述

О Гермесе

С момента запуска ReactNative было подключено и использовано большое количество приложений, включая основной бизнес-процесс крупномасштабных приложений. Поскольку сложность бизнеса продолжает расти, проблемы с производительностью становится невозможно игнорировать.

Анализируя данные о производительности, команда Facebook обнаружила, что движок JavaScript является важным фактором, влияющим на производительность запуска и размер пакета приложения. Поскольку JavaScriptCore изначально был разработан для настольных браузеров, по сравнению с настольными компьютерами, возможности мобильных устройств имеют слишком много ограничений.Чтобы оптимизировать производительность мобильных устройств снизу, команда Facebook решила создать свой собственный движок JavaScript и разработала Hermes, который ограничено ограничениями обзора iOS AppStore, в настоящее время только для платформы Android.

Набор тестовых данных двигателя Hermes был официально предоставлен на конференции Chain React:

  • Время от запуска страницы до действия пользователя (время до взаимодействия: TTI) сокращено с 4,3 до 2,01 с.
  • Размер загружаемого приложения уменьшен с 41 МБ до 22 МБ.
  • Объем памяти уменьшен со 185 МБ до 136 МБ.

Можно обнаружить, что после перехода на Hermes значительно улучшились три ключевых показателя: время загрузки, размер приложения и занятость памяти.

在这里插入图片描述
Поскольку Hermes оптимизирован для мобильных приложений, мы не планируем интегрировать его в какой-либо браузер или серверную инфраструктуру, например Node.js. Существующие механизмы JavaScript по-прежнему предпочтительны в этих средах.

Решение Hermes для оптимизации

При разработке мобильных приложений первая загрузка и запуск, объем памяти и размер приложения являются важными показателями для измерения качества приложения, поэтому Hermes также оптимизирует приложения React Native с учетом этих аспектов.

предварительная компиляция байт-кода

Вообще говоря, механизм JavaScript будет анализировать исходный код JavaScript и генерировать байт-код после его загрузки, а код JavaScript необходимо выполнить после создания байт-кода. Чтобы пропустить этот шаг, Hermes представляет прекомпилятор, который запускается в процессе сборки мобильного приложения. Это дает больше времени для оптимизации байт-кода, делая байт-код меньше и эффективнее. Теперь также можно оптимизировать всю программу, например, выполнить дедупликацию и упаковать таблицы строк.

Байт-код разработан таким образом, что его можно отображать в память и интерпретировать во время выполнения без жадного чтения всего файла. Плохая производительность операций ввода-вывода во флэш-памяти на многих мобильных устройствах низкого и среднего класса значительно увеличивает задержку, поэтому загрузка байт-кода, оптимизированного для объема, из флэш-памяти по запросу может значительно улучшить TTI. Кроме того, поскольку память отображается только для чтения и поддерживается файлами, мобильные операционные системы, не использующие виртуальную память (например, Android), могут очищать эти страницы при нехватке памяти, уменьшая число остановок процессов на устройствах с меньшим объемом памяти.

在这里插入图片描述
Хотя сжатый байт-код немного больше, чем сжатый исходный код JavaScript, Hermes уменьшает общий размер Android-приложения проекта React Native из-за меньшего размера собственного кода Hermes.

Нет JIT

Чтобы увеличить скорость выполнения, популярный движок JavaScript может компилировать часто интерпретируемый код как машинный код, который выполняется мгновенным (JIT) компилятором.

В настоящее время у Hermes нет JIT-компилятора. Это означает, что Hermes не будет очень хорошо работать в некоторых тестах, особенно в тех, которые полагаются на производительность процессора. Это сделано специально: эти бенчмарки едва ли отражают реальную нагрузку мобильных приложений. Мы также провели несколько экспериментов с JIT, но считаем важным сосредоточиться на приведенных выше реальных показателях, если вы хотите получить реальный прирост скорости. Поскольку JIT должны прогреваться при запуске приложения, они вряд ли улучшат TTI и даже могут повредить TTI. Кроме того, JIT увеличивает размер собственного кода и потребление памяти, что негативно влияет на наши основные показатели. JIT может тормозить важные для нас показатели, поэтому мы решили не внедрять JIT.

Политика сбора мусора

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

Поэтому, чтобы максимально оптимизировать память и пространство VA, используемое движком, мы построили сборщик мусора со следующими функциями.Основные меры:

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

Интеграция Гермеса

Быстро начните работу с Hermes

Команда Faceback загрузила инструмент Hermes в npm:hermesvm. Инструмент hermes может напрямую запускать JS-код, преобразовывать байт-код и предоставлять множество параметров для управления настройкой.

Например, ниже показано, как hermesvm выполняет код JS и преобразует функцию байт-кода, код выглядит следующим образом:


// 创建hermes_test文件,内容:print("This is Hermes Demo");
vim hermes_test.js

// 直接执行纯文本js
~/node_modules/hermesvm/osx-bin/hermes hermes_test.js
This is Hermes Demo

// 转换成bytecode
~/node_modules/hermesvm/osx-bin/hermes --emit-binary hermes_test.js -out hermes_test.hbc

// 执行字节码
~/node_modules/hermesvm/osx-bin/hermes hermes_test.hbc
This is Hermes Demo

Интеграция в новый проект

目前 Hermes 是一个可选的 React Native 功能. Если вы хотите включить Hermes, вам необходимо убедиться, что версия вашего проекта React Native выше 0.60.2, а также вам необходимо внести следующие изменения в файл android/app/build.gradle.

project.ext.react = [
  entryFile: "index.js",
  enableHermes: true
]

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

cd android && ./gradlew clean

Затем вы можете разработать и развернуть свое приложение как обычно.

react-native run-android

在这里插入图片描述

отладка

Чтобы обеспечить удобство отладки, мы реализовали поддержку удаленной отладки Chrome через протокол DevTools. На сегодняшний день React Native поддерживает только отладку с помощью прокси-сервера в приложении при запуске кода JavaScript вашего приложения в Chrome. С этой поддержкой можно отлаживать приложение, но синхронные собственные вызовы недоступны в мосте React Native. Поддержка Hermes протокола удаленной отладки позволяет разработчикам подключаться к движку Hermes, работающему на их устройстве, и отлаживать свои приложения, используя тот же движок, что и в рабочей среде. Помимо отладки, мы также рассматриваем возможность реализации дополнительной поддержки протокола Chrome DevTools.

在这里插入图片描述

Сравнение Hermes, JavaScriptCore и V8

После официальной проверки данных ключевые показатели, предложенные командой Faceback, были значительно улучшены по сравнению с исходным решением JavaScriptCore.

Во-первых, по размеру нативного so-файла, необходимой so-библиотеки, на которую опирается RN, Hermes примерно на 16% меньше, чем JavaScriptCore (одна архитектура armeabi сжимается примерно на 0,5M), а V8 намного больше чем Hermes и JavaScriptCore.

在这里插入图片描述
Далее идет флуктуация памяти, возьмемRNTesterПосле входа на страницу RN и перехода на несколько страниц и выхода из инженерного теста можно увидеть колебания памяти, и рост памяти V8 и Hermes должен быть более плавным.
在这里插入图片描述
Далее идут колебания ЦП.Пройдите тест проекта RNTester и войдите на страницу RN, чтобы перейти на несколько страниц и выйти, и сравните колебания ЦП. Hermes значительно лучше, чем V8 и JavaScriptCore. ,Как показано ниже.
在这里插入图片描述

Проблемы с Гермесом

По сравнению с JavaScriptCore у Hermes действительно есть много преимуществ, но он не обязательно лучше, чем JavaScriptCore.По мере тестирования и интеграции постепенно появляются проблемы, привносимые Hermes.

Размер файла байт-кода слишком велик

В результате теста файл байт-кода, скомпилированный Hermes, на 100% больше, чем простой текстовый файл js. Следовательно, выходной пакет RN будет относительно большим, и когда инкрементный пакет RN выдается динамически, эффективность различия также будет снижена из-за различий в двоичном файле.

Чтобы решить эту проблему, в соответствии с характеристиками Hermes, мы изменили свое мышление и поставили компиляцию байт-кода Hermes на стороне клиента.На стороне клиента хранятся как файлы js, так и файлы байт-кода.Если компиляция байт-кода завершена, используйте Hermes, в противном случае по-прежнему используйте JavaScriptCore.

Проект с открытым исходным кодом Hermes предоставляет метод complieJS для компиляции байт-кода, но эта часть кода по умолчанию не упакована в движок Hermes RN.Мы немного интегрируем и упаковываем его и предоставляем через JNI для использования в бизнесе.

Выполнение обычного текста js занимает много времени

Мы позволяем Hermes загружать обычный текст перед преобразованием простого текста js в байт-код на стороне клиента. Но фактический тест показал, что производительность Hermes при загрузке обычного текста почти на 30% ниже, чем у JavaScriptCore. Основная причина заключается в том, что Hermes удаляет JIT-функцию, из-за чего простой текстовый js-код работает медленнее.

Непрерывная оптимизация

Чтобы упростить миграцию Hermes и продолжить поддержку JavaScriptCore на iOS, мы создали JSI — упрощенный API для встраивания движков JavaScript в приложения C++. Этот API позволяет инженерам React Native внедрять собственные улучшения инфраструктуры. Fabric использует JSI, который может опережать рендеринг React Native; TurboModules также использует JSI, который уменьшает размер собственных модулей и может лениво загружаться в соответствии с потребностями приложений React Native.

Ссылки по теме:

hermesengine.dev/

Woohoo.OSCHINA.net/afraid/Hermes- это просто…

woo woo woo.info Q. Talent/article/8JE…