Mobile Development 31 min read

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.

Meituan Technology Team
Meituan Technology Team
Meituan Technology Team
Optimizing Android .so Library Size: Techniques and Practices

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

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Androidbuild toolsELFLTOLinkerSO Optimization
Meituan Technology Team
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.