Optimizing Android .so Library Size: Techniques and Practices
This article explains how Meituan engineers shrink Android native .so libraries by analyzing ELF sections, simplifying dynamic symbols, removing dead code, using link‑time optimization, garbage‑collecting sections, applying size‑focused compiler flags, disabling exceptions/RTTI, and merging or extracting libraries, achieving 30‑60% APK size reductions and faster load times.
Reducing the size of an Android application package (APK) improves user experience and download conversion rates. This article shares practical experience from the Meituan platform on how to optimize the size of native shared libraries (.so files), covering the .so file format, analyzable optimization targets, concrete optimization methods, and engineering considerations.
1. Background
APK size affects download time, installation time, and disk usage. An APK is essentially a zip archive containing dex, assets, resources, and .so files. Common size‑reduction techniques focus on dex, resources, assets, and .so files. Even after applying these techniques, .so files often remain a large portion of the package, prompting further investigation.
2. .so File Format Analysis
A .so file is an ELF (Executable and Linkable Format) binary. It can be viewed from two perspectives:
Linking view – how sections are assembled (compiler/linker perspective).
Execution view – how segments are loaded at runtime (dynamic linker perspective).
Since optimization mainly targets the linking view, the article focuses on sections such as .text, .data, .bss, .rodata, .dynsym, .dynstr, .gnu.hash, .hash, .gnu.version, .gnu.version_d, and .gnu.version_r. The readelf -S command can list all sections of a .so file.
3. Optimizable Content in .so
Based on the analysis, the following optimization directions are identified:
Simplify the dynamic symbol table : Export only necessary symbols (e.g., JNI_OnLoad, JNI_OnUnload, and Java native method symbols). Use RegisterNatives to reduce exported symbols.
Remove dead code : Eliminate code that is never executed in release builds. Be careful with special sections like .init_array.
Optimize instruction length : Allow the compiler to generate shorter instruction sequences.
4. Optimization Techniques
4.1 Simplify Dynamic Symbol Table
Control symbol visibility with -fvisibility=hidden (global) and __attribute__((visibility("hidden"))) (per‑symbol). The static keyword also hides symbols. For static libraries, use the linker flag -Wl,--exclude-libs,ALL to prevent their symbols from being exported. A version script can explicitly list exported symbols, e.g.:
{
global: JNI_OnLoad; JNI_OnUnload; Java_*;
local: *;
};4.2 Remove Unused Code
Enable Link‑Time Optimization (LTO) with -flto to let the linker discard dead code. Use -O3 -flto for Clang or -Os -flto for GCC.
4.3 Enable Garbage Collection of Sections
Pass -Wl,--gc-sections to the linker and compile with -ffunction-sections -fdata-sections so each function and data item resides in its own section, allowing the linker to drop unused sections.
4.4 Use Size‑Optimized Optimization Levels
Clang supports -Oz (or GCC -Os) to prioritize binary size over performance.
4.5 Disable C++ Exceptions and RTTI
If the project does not use exceptions or Run‑Time Type Information, add -fno-exceptions and -fno-rtti to reduce code size.
4.6 Merge and Extract Shared Libraries
Merge rarely used .so files into a single library to reduce symbol tables and PLT/GOT entries. Conversely, extract common static dependencies (e.g., libc++_shared.so) to avoid duplication across multiple .so files.
5. Engineering Practice
Meituan supports many build systems (CMake, ndk‑build, Make, Ninja, GYP, GN). The platform provides a unified configuration to enable .so size optimization regardless of the underlying build tool. Important considerations include:
Export symbols required by dlsym calls.
When using a version script, handle C++ name mangling correctly. Either list mangled symbols directly (e.g., _ZN7MyClass5startEi) or use extern "C++" blocks with demangled names.
After optimization, verify exported symbols with nm -D --defined-only libexample.so on macOS/Linux.
6. Benefits
Optimizing .so files reduces APK size (30%‑60% reduction observed), lowers on‑device storage usage, improves load time, and removes unnecessary exported symbols, enhancing security.
7. Future Work
Investigate ThinLTO to mitigate increased build time.
Provide detailed reports on retained functions/data.
Further improve platform support for .so optimization.
8. References
https://www.cs.cmu.edu/afs/cs/academic/class/15213-f00/docs/elf.pdf
https://llvm.org/docs/LinkTimeOptimization.html
https://gcc.gnu.org/onlinedocs/gccint/LTO-Overview.html
https://sourceware.org/binutils/docs/ld/VERSION.html
https://clang.llvm.org/docs
https://gcc.gnu.org/onlinedocs/gcc
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Meituan Technology Team
Over 10,000 engineers powering China’s leading lifestyle services e‑commerce platform. Supporting hundreds of millions of consumers, millions of merchants across 2,000+ industries. This is the public channel for the tech teams behind Meituan, Dianping, Meituan Waimai, Meituan Select, and related services.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
