Impact on App Memory
After integrating HybridCLR, the impact on App runtime memory mainly consists of the following parts:
- Dynamic Heap Memory
- (Increase) Memory occupied by maintaining bridge function mappings
- (Increase) Interpreter thread data stack and frame stack memory
- (Increase) Memory occupied by instruction optimization module (only available in commercial versions)
- (Increase) Additional metadata memory occupied by DHE (only available in Ultimate version)
- (Decrease) Optimized libil2cpp metadata memory management (only available in commercial versions). Significantly reduces metadata memory overhead
- Static Code Segment Memory
- (Increase) Bridge function MethodBridge.cpp increases binary code size after compilation
- (Increase) Additional code bloat introduced by DHE code injection increases binary code size (only available in Ultimate version)
- (Decrease) After converting AOT assemblies to regular interpreted assemblies (excluding DHE assemblies, as DHE assemblies also need to be compiled into AOT), reduces binary code size
Although the increased static Code segment memory size will be displayed in the App's total memory, it does not represent the actual memory usage of the code. Static Code segment code is loaded on demand, and the actual memory usage should be checked with Resident Set Size (RSS)
data.
We built a test project to test the actual impact of HybridCLR on the package.
Testing
We tested the memory of Android Armv8 platform apk built with Unity 2021 version.
The AOT part of the test project fully includes the following frameworks and libraries:
- mscorlib, System, System.Core
- UnityEngine.dll, UnityEngine.CoreModule.dll, UnityEngine.UI.dll, UnityEngine.PhysicsModule.dll
- GameFramework
- HybridCLR.Runtime.dll
- Luban
- UniTask
- YooAsset
We counted the total size of AOT module dlls after building the apk: 12.0M in total.
The hot update part of the test project code consists of the following parts:
- Unit test project code
- Configuration code generated by Luban
The compiled HotUpdate.dll is 1216k.
The bridge function MethodBridge.cpp size is 15088K.
We compared the memory usage in the following scenarios:
- NotHybridCLR-NotHotUpdateCode Not integrated with HybridCLR, does not include HotUpdate code
- NotHybridCLR-HotUpdateCode Not integrated with HybridCLR, includes HotUpdate code
- HybridCLR Community-NotHotUpdateCode Integrated with HybridCLR community version, does not include HotUpdate code, normally generates bridge function files
- HybridCLR Community-HotUpdateCode Integrated with HybridCLR community version, includes HotUpdate code, normally generates bridge function files
- HybridCLR Professional-NotHotUpdateCode Integrated with HybridCLR professional version, does not include HotUpdate code, normally generates bridge function files
- HybridCLR Professional-HotUpdateCode Integrated with HybridCLR professional version, includes HotUpdate code, normally generates bridge function files
- HybridCLR Ultimate-NotHotUpdateCode Integrated with HybridCLR ultimate version, does not include HotUpdate code, normally generates bridge functions
- HybridCLR Ultimate-HotUpdateCode-LoadOriginalDifferentialHybridAssembly Integrated with HybridCLR ultimate version, includes HotUpdate code, normally generates bridge functions, HotUpdate assembly unchanged, uses RuntimeApi::LoadOriginalDifferentialHybridAssembly to load HotUpdate
- HybridCLR Ultimate-HotUpdateCode-LoadDifferentialHybridAssembly Integrated with HybridCLR ultimate version, includes HotUpdate code, normally generates bridge functions, HotUpdate assembly unchanged, uses RuntimeApi::LoadDifferentialHybridAssembly to load HotUpdate
Test results are as follows:
Build Method | App Heap Memory(K) |
---|---|
NotHybridCLR-NotHotUpdateCode | 51343 |
NotHybridCLR-HotUpdateCode | 59400 |
HybridCLR Community-NotHotUpdateCode | 53592 |
HybridCLR Community-HotUpdateCode | 65695 |
HybridCLR Professional-NotHotUpdateCode | 50380 |
HybridCLR Professional-HotUpdateCode | 62235 |
HybridCLR Ultimate-NotHotUpdateCode | 52531 |
HybridCLR Ultimate-HotUpdateCode-LoadOriginalDifferentialHybridAssembly | 61276 |
HybridCLR Ultimate-HotUpdateCode-LoadDifferentialHybridAssembly | 65655 |
Based on the above test project, we can roughly draw the following conclusions:
- (Increase) Bridge functions occupy approximately
{MethodBridge.cpp file size} * 0.1
size of heap memory - (Increase) Each thread that has executed hot update code occupies approximately 1.2M memory
- (Increase) Instruction optimization module (only available in commercial versions) occupies about 700K
- (Increase) Additional metadata memory occupied by DHE (only available in Ultimate version). Approximately
{total AOT assembly size + total DHE assembly size} * 0.12
size of memory - (Increase) Bridge function MethodBridge.cpp increases binary code size after compilation. Approximately
{MethodBridge.cpp file size} * 0.3
size - (Increase) Additional code introduced by DHE (only available in Ultimate version) code injection increases binary code size. Approximately
{DHE assembly size} * 0.86
size - (Decrease) Optimized libil2cpp metadata memory management (only available in commercial versions), reduces
10-25%
of metadata memory overhead - (Decrease) After converting AOT assemblies to regular interpreted assemblies (excluding DHE assemblies, as DHE assemblies also need to be compiled into AOT), reduces binary code size. Approximately
{hot update assembly size} * 5.2
size
Summary
Community Version
- Additional heap memory is approximately
{MethodBridge.cpp size} * 0.1
+1.2M * {number of threads that executed interpreted code}
+{hot update assembly size} * 2.2
- Increase in code segment memory is approximately
{MethodBridge.cpp size} * 0.3
-{hot update assembly size} * 5.2
Generally speaking, after integrating the community version, binary code will decrease, meaning the increased code segment memory
is usually a negative value.
Professional Version
- Additional heap memory is approximately
{MethodBridge.cpp size} * 0.1
+ 0.7M (instruction optimization module memory) +1.2M * {number of threads that executed interpreted code}
+{hot update assembly size} * 1.6
-{total assembly size} * 0.2
- Increase in code segment memory is approximately
{MethodBridge.cpp size} * 0.3
-{hot update assembly size} * 5.2
Generally speaking, after integrating the professional version, binary code will decrease, meaning the increased code segment memory
is usually a negative value.
Ultimate Version
- Additional heap memory is approximately
{MethodBridge.cpp size} * 0.1
+ 0.7M (instruction optimization module memory) +1.2M * {number of threads that executed interpreted code}
+{hot update assembly size} * 3 (questionable, seems significantly overestimated)
+{total AOT assembly size + total DHE assembly size} * 0.12
-{total assembly size} * 0.2
- Increase in code segment memory is approximately
{DHE assembly size} * 0.86
+{MethodBridge.cpp size} * 0.3
Due to the limited scale of the sample project, the test results may not match real projects. The {hot update assembly size} * 3
portion of memory is clearly overestimated, please refer to actual projects.