Click on “Developer Technology Front” and select “Star label 🔝”
Looking at the star icon | | message, true love
Mobile apps are becoming more onerous and complex at the same time. Developers often run into performance issues like lag when adding new features to their apps. While there are many reasons for performance issues, users don’t care, they just want a smooth experience when they use the app on any device.
In order to improve the performance of Facebook apps, our team constantly improves our JavaScript code and platform. When analyzing the performance data, we found that the JavaScript engine itself was an important factor affecting startup performance and application package size. With this data, we realized that we had to optimize JavaScript performance in a mobile environment that was more restrictive than the PC. After trying various scenarios, we built a new JavaScript engine: Hermes. It aims to improve application performance, focuses on React Native apps, and works well on mobile devices that have little memory, slow storage, and low computing power.
At Chain React 2019, we launched the Hermes JavaScript engine. We’ve opened source the Hermes engine and the Hermes integration for React Native. We are excited to work with the open source community to enable developers to start using Hermes immediately.
For javascript-based mobile applications, the user experience depends on the following metrics:
-
The time available to the application, called interaction time (TTI)
-
Size of data to download (APK size on Android)
-
Memory usage
MatterMost, which runs the React Native app on The Google Pixel, reflects the performance of popular smartphones in markets like India.
It’s worth noting that these metrics have little to do with the CPU usage of the engine when executing JavaScript code. Focusing on these metrics means we need to develop strategies and trade-offs that are different from most JavaScript engines today. So our team had to design and build Hermes from scratch. By focusing on these metrics, our implementation brought substantial improvements to the React Native application.
Since Hermes is optimized for mobile applications, we have no plans to integrate it into any browser or server infrastructure such as Node.js. Existing JavaScript engines are still preferred in these environments.
Mobile devices have many limitations, such as less memory and slower flash memory. Therefore, we made some targeted optimization designs at the architecture level, including:
Typically, JavaScript engines parse JavaScript source code and generate bytecodes after loading, and JavaScript code needs to start executing after bytecodes are generated. To skip this step, Hermes introduces a precompiler that runs during the mobile application build process. This can take longer to optimize bytecode, making it smaller and more efficient. It is now possible to optimize the entire program, such as removing duplicate data and packaging string tables.
Bytecode is designed so that it can be mapped to memory and interpreted at run time without having to eagerly read the entire file. Poor-performing flash I/O on many mid – and low-end mobile devices significantly increases latency, so volumeoptimized bytecode loading from flash on demand can significantly improve TTI. In addition, because memory is mapped read-only and supported by files, mobile operating systems that do not use virtual memory, such as Android, can clear these pages when they run low on memory, thereby reducing process killing on devices with less memory.
Although the compressed bytecode is slightly larger than the compressed JavaScript source code, Hermes reduces the size of Android React Native apps overall due to the smaller size of the Native Hermes code.
To speed up execution, popular JavaScript engines can lazily compile frequently interpreted code into machine code. This work is performed by a JUST-in-time (JIT) compiler.
Hermes does not currently have a JIT compiler. This means Hermes will not perform well in some benchmarks, particularly those that rely on CPU performance. This design is deliberate: these benchmarks hardly reflect the actual workloads of mobile applications. We have done some experiments with JIT, but we believe that to achieve real speed improvements, we need to focus on the above realistic metrics. Because JIts must warm up at application startup, they are difficult to improve TTI and may even damage TTI. In addition, JIT increases native code volume and memory consumption, which negatively impacts our key metrics. JIT can be a drag on the metrics we care about most, so we choose not to implement it. At the expense of this, we focus more on Hermes interpreter performance.
Efficient use of memory on mobile devices is especially important. Low-end devices have limited memory and often no operating system virtual memory, which forces applications that use too much memory to be killed. When an application is killed and used again, it needs to be restarted slowly, and background functions are affected. In early testing we learned that virtual address (VA) space, especially contiguous VA space, can be a limited resource when running large applications on 32-bit devices, and lazy allocation with physical pages is not helpful.
To maximize the memory and VA space used by the engine, we built a garbage collector with the following features:
-
Allocation on Demand: VA space is allocated in blocks only when needed.
-
Discontinuous: THE VA space does not have to be in a single memory range, which avoids resource limitations on 32-bit devices.
-
Move: Being able to move objects means you can defragment memory and return blocks that are no longer needed to the operating system.
-
Generational: Not scanning the entire JavaScript heap each time GC, reducing GC time.
To start using Hermes, developers need to make some changes to their build.gradle file and recompile the application. See the full instructions for migrating to Hermes on React Native.
project.ext.react = [ entryFile: "index.js", enableHermes: true]
Copy the code
High iteration speed is one of the main advantages of javascript-based platforms, but precompilation of bytecode diminishes this advantage. For fast reloading, the Hermes debug version does not use precompilation; Instead, they lazily generate bytecode on the device. This allows developers to iterate quickly using Metro or other pure JavaScript code sources. The trade-off is that lazily compiled bytecode does not include all the optimized features of a production build. In fact, while we were able to notice a performance gap, we found that this approach was sufficient to provide a good developer experience without compromising production metrics.
Hermes is currently targeting the ES6 specification and we intend to keep up with the latest JavaScript specifications as we develop. To optimize the engine size, we chose not to support language features that don’t seem to be commonly used in React Native applications, such as proxies and Native eval(). The full list can be found on GitHub.
To provide a great debugging experience, we implemented remote debugging support for Chrome through the DevTools protocol. As of today, React Native only supports in-app proxy debugging when running your app’s JavaScript code in Chrome. With this support you can debug your application, but the React Native bridge doesn’t sync Native calls. Hermes’s support for remote debug protocols allows developers to connect to the Hermes engine running on their device and debug their applications natively using the same engine as in production. In addition to debugging, we are also considering implementing additional support for the Chrome DevTools protocol.
To simplify migration of Hermes and continue to support JavaScriptCore on iOS, we built JSI; This is a lightweight API for embedding JavaScript engines in C++ applications. This API enables React Native engineers to implement their own infrastructure improvements. Fabric uses JSI, which preempts React Native rendering; TurboModules also uses JSI, which reduces the size of Native modules and can be loaded lazily according to the needs of React Native applications.
React Native was our initial use case and the focus of most of our work to date, but we didn’t stop there. We intend to build time and memory analysis tools to help developers improve their applications more easily. We want to fully support the Visual Studio Code debugger protocol and introduce new features such as completion. We also want to develop other mobile use cases.
No open source project can succeed without community participation. We want you to try Hermes in your React Native app, see how it works, and help us democratize Hermes. In particular, we want to know which use cases the community thinks work best, and it doesn’t matter whether a use case is React Native or not.
We would like to thank Tzvetan Mikov, Will Holen and the rest of the Hermes team for their important contributions to the build and open source efforts at Hermes.
English text: https://code.fb.com/android/hermes/
—END—
Select the “Developer Technology Frontier” star label 🔝, content is accessible at a touch. Click on the article for more surprises!
Developer Tech Front is an excellent guide for developers to experience and grow by gathering tech front news and industry trends.
History is recommended
Mobile QQ open source dynamic framework based on Flutter, MXFlutter
Zhang Yiming, CEO of Bytedance, blasted HR, saying, “I can’t even get in according to this requirement!”
Another programmer in Southeast Asia!
Click here to unlock more surprises!