Mobile Development 11 min read

Optimizing Rust Android Dynamic Library Size: Strategies and Results

This article details how the author reduced the size of a Rust‑based Android JNI dynamic library from 495 KB to 95 KB by adjusting compiler optimization levels, enabling LTO, switching panic handling to abort, removing unused strings, applying panic_immediate_abort, and crafting a custom linker script, while providing code snippets and size comparison tables.

JD Tech Talk
JD Tech Talk
JD Tech Talk
Optimizing Rust Android Dynamic Library Size: Strategies and Results

Background

The size of an application package directly impacts download rates, installation time, and device storage usage; Google Play reports that each 6 MB increase reduces conversion by 1 %.

The author’s Rust‑written JNI library initially weighed 495 KB after stripping, prompting a series of size‑reduction measures.

Why Rust?

Rust offers stability and safety for JNI code, eliminating many memory‑management bugs and making reverse engineering harder, though its default build produces relatively large binaries.

Optimization Strategies

Adjust Optimization Level

Changing the Cargo profile from the default opt-level = 3 to opt-level = 'z' targets minimal binary size.

[profile.release]
opt-level = 'z'

Result: size reduced from 495 KB to 437 KB.

Enable LTO

Link‑time optimization removes redundant code at the cost of longer link times.

Cargo.toml
[profile.release]
opt-level = 'z'
lto = true

Result: size marginally decreased to 436 KB.

Abort on Panic

Replacing the default panic backtrace with panic = 'abort' eliminates the extra unwind information.

[profile.release]
opt-level = 'z'
lto = true
panic = 'abort'

Result: size dropped to 366 KB.

Remove Unused Strings & Enable panic_immediate_abort

By trimming unnecessary string literals in third‑party crates and disabling generated formatting strings, further reductions are achieved.

.cargo/config.toml
[unstable]
build-std-features = ["panic_immediate_abort"]
build-std = ["std","panic_abort"]

Result: size fell to 135 KB, with the author’s core code accounting for 52 % of the total.

Linker Script Optimization

Analyzing ELF sections with readelf -S revealed removable sections. A custom linker script keeps only essential sections and discards the rest.

PHDRS
{
  headers PT_PHDR PHDRS ;
  text PT_LOAD FILEHDR PHDRS ;
  data PT_LOAD ;
  dynamic PT_DYNAMIC ;
}
ENTRY(Reset);
EXTERN(RESET_VECTOR);
SECTIONS
{
  . = SIZEOF_HEADERS;
  .text : { *(.text .text.*) } :text
  .rodata : { *(.rodata .rodata.*) } :text
  . = . + 0x1000;
  .data : { *(.data .data.*) *(.fini_array .fini_array.*) *(.got .got.*) *(.got.plt .got.plt.*) } :data
  .bss : {*(.bss .bss.*)} :data
  .dynamic : { *(.dynamic .dynamic.*) } :data :dynamic
  /DISCARD/ :
  {
    *(.ARM.exidx .ARM.exidx.*);
    *(.gnu.version .gnu.version.*);
    *(.gnu.version_r .gnu.version_r.*);
    *(.eh_frame_hdr .eh_frame .eh_frame_hdr.* .eh_frame.* );
    *(.note.android.ident .note.android.ident.*);
    *(.comment .comment.*);
  }
}

Updating Cargo configuration to use the new script further reduced the binary to 95 KB, meeting the target size requirement.

Summary

Compilation Option

Size

strip

495 KB

strip + opt-level = 'z'

437 KB

strip + opt-level = 'z' + lto

436 KB

strip + opt-level = 'z' + lto + panic = 'abort' + code trimming + panic_immediate_abort

135 KB

All above + section removal (linker script)

95 KB

The techniques described are applicable to other languages such as C/C++ and can serve as a reference for developers needing to shrink native libraries for mobile platforms.

Mobile DevelopmentAndroidrustLTOBinary Size OptimizationLinker Script
JD Tech Talk
Written by

JD Tech Talk

Official JD Tech public account delivering best practices and technology innovation.

0 followers
Reader feedback

How this landed with the community

login 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.