Hi everyone! The Unity Android platform team here. We know that game performance in production is of utmost importance to you and your games. In an extremely competitive landscape, every little boost counts to help make a game stand out. The startup time of that first launch can make or break a user’s first experience with your product. And with the fragmentation of the Android ecosystem, CPU bottlenecking is also often a frequent encounter.
As a result, we have recently been doing deep performance work on Android Runtime and wanted to share our findings with the community. We researched and successfully integrated Link Time Optimization (LTO) optimizations into Unity 6.5 for Android. Our work involved investigating the performance impact on two core native libraries: libunity.so (the Unity engine runtime) and libil2cpp.so (your compiled C# game code). We focused on app startup time and per-frame runtime performance. With these features now available in Unity 6.5, we want to share our data and show you how to implement them in your own projects.
Summary of Findings
Across multiple real-world Unity games and a range of Android devices, these optimizations delivered strong, consistent results. ThinLTO on libunity.so brings up to 7.3% faster startup and nearly 4% better CPU frame times for some projects. If you also enable IL2CPP Master LTO for your release builds, the gains compound further.
- ThinLTO on libunity.so (Engine Runtime)
- Gains: Significant reduction in Time to Initial Display (TTID: -7.3%) and CPU Main Thread Frame Time (-3.7%).
- Trade-offs: Negligible build time increase; +3.3% APK size.
- Setup: Set Link Time Optimization to Thin in the Android Build Profile. Requires Strip Engine Code to be disabled. (Docs)
- ThinLTO on libil2cpp.so (IL2CPP Master LTO Mode)
- Gains: Meaningful reduction in Time to Full Display (TTFD: -5.7%). Best for projects with heavy C# Generics.
- Trade-offs: Substantial increase in build time (+30-35%); +1.6% total APK size.
- /Setup: Best reserved for production release builds. Enable by setting C++ Compiler Configuration to Master in Project Settings > Player > Android > Script Compilation. (Docs)
What Is LTO?
When the C++ compiler builds a native library, it optimizes each source file in isolation. Link Time Optimization changes that: it defers some optimization work to the link stage, where the linker has a complete view of the whole program and can make smarter decisions, such as inlining functions across compilation unit boundaries, eliminating dead code more aggressively, and improving register allocation across call sites.
ThinLTO is a scalable variant developed by LLVM. Rather than loading the entire program into memory at once (as Full LTO does), ThinLTO works with lightweight module summaries and parallelizes cross-module optimization. This keeps link times practical while capturing most of the real-world performance wins.
Both libunity.so and libil2cpp.so are compiled with Clang and linked with LLD, which makes ThinLTO a natural fit for both.
What We Did and What We Found
Our primary focus was on two dimensions of performance: startup time (how quickly the app reaches a usable state after launch) and per-frame runtime performance (how efficiently the main thread executes each frame once the game is running). These are the metrics that most directly affect player experience on Android, and they are where LTO’s cross-module inlining tends to have the most impact.
ThinLTO on libunity.so
The first change was enabling ThinLTO on libunity.so, the Unity engine runtime. Because ThinLTO operates at the link step with no recompilation, the impact on build time is negligible. The results were consistently positive across all projects we tested.
Test setup: 5 projects, 10 cold-start runs per configuration on several devices. ARM64 release builds with Strip Engine Code disabled.
| Metric | Baseline | ThinLTO | Change (lower is better) |
|---|---|---|---|
| TTID (Time to Initial Display) | 247.96 ms | 229.90 ms | -7.3% |
| TTFD (Time to Full Display) | 1114.86 ms | 1101.48 ms | -1.2% |
| CPU Main Thread Frame Time | 13.88 ms | 13.36 ms | -3.7% |
libunity.so binary size |
58.2 MB | 60.1 MB | +3.3% |
| Build time impact | - | - | Negligible |
The binary size increase comes from the linker retaining more inlined code at each call site rather than sharing function bodies. In practice, this is a small trade-off for a consistent, low-risk runtime improvement, and the size difference gets smaller the bigger the project already is.
Available from: Unity 6000.5.0a1
Note: Currently applies to release builds with Strip Engine Code disabled. We are actively investigating extending this to Strip Engine Code enabled builds as well.
ThinLTO on libil2cpp.so (IL2CPP Master LTO Mode)
The second change was more involved. IL2CPP generates C++ from your C# code, and the resulting compilation units are numerous and tightly interconnected. Enabling ThinLTO there required changes to how the IL2CPP compiler driver invokes the toolchain, pairing LTO with -O2 at the link optimization stage.
While the performance gains are meaningful, this mode comes with some trade-offs: it substantially increases build time and causes a slight, C# code-dependent increase in executable size. Therefore, this setting is best reserved for production release builds. Projects with heavy use of C# generics tend to see the strongest gains, since -O2 is especially effective at optimizing the templated and inlined code paths that IL2CPP generates for generics.
Test setup: 6 projects, 10 cold-start runs per configuration on several devices. ARM64 release builds.
| Metric | Baseline | ThinLTO + -O2 (Master) | Change (lower is better) |
|---|---|---|---|
| TTID (Time to Initial Display) | 443.84 ms | 426.97 ms | -3.8% |
| TTFD (Time to Full Display) | 1228.76 ms | 1158.28 ms | -5.7% |
| CPU Main Thread Frame Time | 10.05 ms | 9.83 ms | -2.3% |
libil2cpp.so binary size |
37.26 MB | 44.23 MB | +18.7% |
| Total APK size | 416.84 MB | 423.37 MB | +1.6% |
| Build time | ~866 s | ~1124 s | +30-35% |
Available from: Unity 6000.5.0a7
How to enable the new optimization options
ThinLTO on libunity.so
This is opt-in via the Link Time Optimization option in the Android Build Profile window.
Step 1: Open the Android Build Profile window and set the build type to Release (Development Build checkbox disabled).
Step 2: In the same window, find the Link Time Optimization dropdown and set it to Thin.
Step 3: Confirm that Strip Engine Code is disabled. Go to Edit > Project Settings > Player > Android > Other Settings and make sure Strip Engine Code is unchecked.
ThinLTO on libil2cpp.so (IL2CPP Master LTO Mode)
Step 1: Open Edit > Project Settings > Player, go to the Android tab, and scroll to Other Settings.
Step 2: Under Script Compilation, set C++ Compiler Configuration to Master. LTO is only applied under the Master configuration; setting LTO mode while on Release or Debug has no effect.
Going further: If you want to experiment beyond the defaults, Unity lets you pass additional flags to the IL2CPP compiler via SetAdditionalIl2CppArgs. For example, you could try -flto=full for Full LTO or a higher optimization level like -O3, though results will vary by project and build times will increase further.
In Unity 6.6, we are also introducing a new dropdown under C++ Compiler Configuration that lets you toggle between Thin and Full LTO, giving you the flexibility to experiment and find the optimal setting for your project.
Things to Keep in Mind
- Build time: IL2CPP Master LTO will add roughly 30-35% to your build time. Treat it as a release-build-only setting, something you turn on for final QA candidates and store submissions.
- Binary size: In our tests
libil2cpp.sogrows by roughly 18.7% (~1.6% total APK). This is the cost of aggressive inlining across generic instantiations. Check your download size budget before enabling, especially if you use Play Asset Delivery with tight size targets. libunity.soThinLTO is consistently low-risk: Across all tested projects this delivered positive results with minimal trade-offs.- Strip Engine Code:
libunity.soThinLTO currently requires Strip Engine Code to be disabled. We are researching extending coverage to Strip Engine Code enabled builds, since we know most users have this setting on. - Results are project-dependent: Projects heavy on C# generics will see the largest gains from IL2CPP Master LTO. GPU-bound or asset-streaming-heavy projects will still see improvements but on a smaller scale may see smaller improvements. We recommend trialling those options on a phased release A/B testing track to get better insights on runtime behavior across the varied Android devices.
Tell Us What You Find!
Every game is different. Our benchmarks span a diverse set of projects, but real-world results vary by project size, C# usage patterns, and target devices. We would love to hear how these optimizations perform for you.
We are continuing to invest in Android runtime performance and your feedback helps us decide what to tackle next. Happy optimizing!
– The Unity Android Platform Team



