Memory management is arguably the most complex subsystem in the Linux kernel. In the context of Android, it is also the most highly tuned, as smartphones do not have the luxury of swapping memory to massive, fast NVMe drives like desktop PCs.
Virtual Memory and Pages
When a C++ program or Java app on Android asks to allocate 1MB of RAM, the kernel does not give it physical RAM directly. Instead, it provides Virtual Memory.
The kernel maps virtual memory addresses to physical RAM chips using Page Tables. Memory is divided into 4KB chunks called Pages.
If a process tries to read a virtual page that has not been mapped to physical RAM yet, the CPU triggers a "Page Fault". The kernel catches this fault, pauses the process, rapidly allocates a physical block of RAM, updates the page table, and resumes the process. This is known as "Demand Paging."
Viewing Memory Stats
You can view how much memory your Android system is using at a granular level:
adb shell cat /proc/meminfo
This will output values like MemTotal, MemFree, Buffers, and Cached, giving you insight into how much RAM the kernel is holding onto.
The Buddy Allocator
To track which physical pages are free and which are in use, the kernel uses the Buddy Allocator algorithm.
It groups contiguous free pages into blocks of powers of two (1 page, 2 pages, 4 pages, 8 pages).
- If the kernel needs 2 pages, but only an 8-page block is available, it splits the 8-page block into two 4-page buddies.
- It then splits one 4-page buddy into two 2-page buddies.
- When memory is freed, the allocator attempts to merge buddies back into larger contiguous blocks.
This algorithmic approach minimizes severe memory fragmentation, which is critical for an operating system that might run for months without a reboot.
The Android Low Memory Killer (LMK)
Standard Linux environments handle running out of memory by using a swap file on the hard drive. Because smartphone flash memory is relatively slow and degrades quickly with constant writes, Android completely disables traditional hard-drive swapping (though it does use ZRAM, which compresses memory in RAM).
When an Android device runs out of physical RAM, it relies on the Low Memory Killer (LMK) daemon.
The ActivityManagerService (AMS) assigns an Out-Of-Memory Adjustment score (oom_score_adj) to every running app. The score ranges from -1000 to 1000.
- System Server:
-900(Never kill) - Foreground App:
0(Highly protected) - Visible Background App:
100to200(Somewhat protected) - Cached Background App:
900to1000(Expendable, kill immediately)
The Assassination Flow
When the kernel detects that free RAM has dropped below a critical threshold:
- The kernel wakes up the
lmkd(Low Memory Killer Daemon) user-space process. lmkdsearches the process list for the app with the highestoom_score_adjvalue.- It instantly sends a
SIGKILLsignal to that process, terminating it without warning to reclaim its memory.
If you ever notice a game reloading from scratch after you briefly switched to the camera app, it is because the LMK daemon assassinated the game to free up the hundreds of megabytes of RAM required by the camera's image processing algorithms.