showmap & meminfo)This guide covers how to measure and interpret Android Runtime (ART)-related memory usage in managed processes, focusing on key artifacts like .dex, .odex, .art, and the Java heap. Understanding these mappings can help quantify resource costs and impact, and guide related optimizations to app bytecode, compiled code, and allocation behavior.
showmap: Displays the virtual memory map of a process. It provides the most detailed view of what files and anonymous memory regions are mapped, their permissions, and their memory consumption (PSS/RSS).dumpsys meminfo: Provides a high-level summary of memory usage, categorizing it into buckets like “Java Heap”, “Code”, “Stack”, and specific mmap types.showmapIdentify the Process ID (PID):
adb shell pidof system_server # Output example: 1543
Run showmap (Root may be required for full details):
adb root adb shell showmap 1543 > system_server_showmap.txt`
Tip: To merge same-named maps and sort by their total private memory (clean + dirty), you can pipe the output as follows:
adb shell showmap 1543 \ | awk -e '{ printf("%5d %s\n", $6 + $7, $0) }' \ | sort -k1 -rn \ > system_server_showmap_sorted.txt
Let's look at an example subset of the output you might see from a showmap command:
virtual shared shared private private size RSS PSS clean dirty clean dirty swap swapPSS object ------- -------- -------- -------- -------- -------- -------- -------- -------- ---------------- ... 38832 6440 430 6380 0 60 0 0 0 /system/framework/framework-res.apk 11796 11072 888 10740 0 332 0 0 0 /apex/com.android.art/javalib/core-oj.jar 8300 8300 4200 8200 0 88 12 0 0 /system/framework/oat/arm64/services.odex 648 644 324 640 0 4 0 0 0 /system/framework/oat/arm64/services.vdex 3072 3064 285 0 2796 0 268 0 0 [anon:dalvik-/system/framework/boot.art] 1048576 65652 65652 0 0 0 65652 0 0 [anon:dalvik-main space] 58836 300 300 0 0 0 300 0 0 [anon:dalvik-non moving space] 6700 6700 456 0 6284 0 416 0 0 [anon:dalvik-zygote space] ...
Private pages + (Shared pages / Number of sharers)ART maps various file types into memory. Understanding them helps diagnose if memory usage comes from code, resources, or the heap.
.dex / .apk / .jar (Bytecode & Resources)Description:
.apk: By default, DEX bytecode should be stored uncompressed in the APK. This allows the runtime to mmap the dex directly from the APK, creating a clean mapping backed by the APK file itself, saving memory compared to extracting it. This mapping will also contain other pages for app resources (e.g., resources.arsc) and assets..jar: Boot classpath or other system libraries.Mapping: Mostly clean (read-only), though not always for certain non-ART components of APKs.
Why it matters: Large mappings of dex/apk/jar files often point to unoptimized or poorly optimized app bytecode and resources. See this guide for best practices on related optimizations. Reducing the size of shipped bytecode and resources can dramatically reduce the app's memory footprint at runtime.
Example:
virtual shared shared private private size RSS PSS clean dirty clean dirty swap swapPSS object ------- -------- -------- -------- -------- -------- -------- -------- -------- ---------------- 38832 6440 430 6380 0 60 0 0 0 /system/framework/framework-res.apk 11796 11072 888 10740 0 332 0 0 0 /apex/com.android.art/javalib/core-oj.jar
.art (App Image / Boot Image)Description: Pre-initialized class/object “snapshots” to improve app startup. Instead of loading commonly used classes at every launch, ART maps these objects directly into the heap.
Mapping: Typically private dirty or shared dirty (if shared with zygote). The image files are stored compressed on disk by default, and must be decompressed into the heap and patched at runtime for security (ASLR).
Why it matters: As app images are dirty mappings, care should be taken to avoid unnecessarily increasing their size. Follow best practices to ensure classes are lean and minified, and avoid bundling overly broad or poorly tuned baseline profiles.
Example:
virtual shared shared private private size RSS PSS clean dirty clean dirty swap swapPSS object ------- -------- -------- -------- -------- -------- -------- -------- -------- ---------------- # Boot image (shared across apps from the zygote) 3072 3064 285 0 2796 0 268 0 0 [anon:dalvik-/system/framework/boot.art] # App image (private to the app) - Note for a background app, this may be entirely in swap as below! 22944 0 0 0 0 0 0 22940 22940 [anon:dalvik-/data/user/0/com.android.foo/cache/oat_primary/arm64/base.art]
Note: You may also see a small, clean file mapping for these images (for referencing the header), but the actual heap data appears as an anonymous mapping named
[anon:dalvik-...art].*
.oat / .odex (Compiled Code)Description: Contains AOT-compiled native machine code (ELF format) and some metadata.
Mapping: Mostly clean (executable code).
Why it matters: The size of these artifacts in memory is a function of how much code is compiled (typically dictated by the profile with speed-profile compilation), and how much is needed at runtime for execution. The best way to minimize memory impact is to ensure that:
.dex has been fully optimized and minified.Example:
virtual shared shared private private size RSS PSS clean dirty clean dirty swap swapPSS object ------- -------- -------- -------- -------- -------- -------- -------- -------- ---------------- 8300 8300 4200 8200 0 88 12 0 0 /system/framework/oat/arm64/services.odex
.vdex (Verified Dex)Description: Contains verification dependencies. If the APK ships with compressed DEX (which prevents direct mapping), the system extracts the uncompressed DEX bytecode into the .vdex file during installation to allow for mapping.
Mapping: Mostly clean (read-only)
Why it matters: A large vdex mapping often indicates that the app is shipping compressed dex, which should be avoided in favor of clean uncompressed dex bundled in the APK.
Example
virtual shared shared private private size RSS PSS clean dirty clean dirty swap swapPSS object ------- -------- -------- -------- -------- -------- -------- -------- -------- ---------------- 648 644 324 640 0 4 0 0 0 /system/framework/oat/arm64/services.vdex
Anonymous memory isn't backed by a file. In Android/ART, these have specific names, typically prefixed with [anon:dalvik-...].
[anon:dalvik-...])Description: The Java heap is a function of runtime allocations and the garbage collector. See this guide for a more exhaustive overview of the GC, how it operates, and what the means for app development. Allocations can end up in one of the following buckets:
[anon:dalvik-main space]: The primary Java heap. This is where standard objects live.[anon:dalvik-large object space]: For very large primitive arrays and strings (LOS).[anon:dalvik-zygote space]: The heap inherited from Zygote. Typically “shared dirty”.[anon:dalvik-non moving space]: Memory for objects that must not move or where moving should be avoided (e.g., certain JNI critical objects, some internal primitive array allocations).Why it matters: High heap utilization, excessive heap churn, and memory leaks, can all lead to poor app performance. This guide outlines several best practices for minimizing heap usage.
Example:
virtual shared shared private private size RSS PSS clean dirty clean dirty swap swapPSS object ------- -------- -------- -------- -------- -------- -------- -------- -------- ---------------- 1048576 65652 65652 0 0 0 65652 0 0 [anon:dalvik-main space] 58836 300 300 0 0 0 300 0 0 [anon:dalvik-non moving space] 6700 6700 456 0 6284 0 416 0 0 [anon:dalvik-zygote space]
Note: The
virtual size(1GB here) is the reserved maximum heap size, butRSS(65MB) is what's actually used.*
[anon:dalvik-LinearAlloc]: Internal storage for loaded classes and methods.[anon:dalvik-card table]: GC accounting structure.[anon:dalvik-bitmap...]: GC live object bitmaps./memfd:jit-cache)Description: Holds native code compiled at runtime by the JIT (Just-In-Time) compiler.
Mapping: Executable, anonymous (or memfd backed).
Why it matters: ART generally tries to find the right balance between AOT and JIT using profile-guided optimization. A large JIT cache can occur if the app has not been speed-profile compiled (check via dumpsys package dexopt).
Example:
virtual shared shared private private size RSS PSS clean dirty clean dirty swap swapPSS object ------- -------- -------- -------- -------- -------- -------- -------- -------- ---------------- 131072 1308 656 0 1304 0 4 0 0 /memfd:jit-cache (deleted)
[anon:scudo:...] or [anon:libc_malloc])Description: Allocations from C++ malloc/new. Android 11+ uses the Scudo allocator.
Mapping: Mostly private dirty, with shared dirty bits from the zygote. While most of ART's memory usage is bucketed into the mappings outlined above, the runtime itself (implemented in C++) can use the native heap for basic execution.
Example:
virtual shared shared private private size RSS PSS clean dirty clean dirty swap swapPSS object ------- -------- -------- -------- -------- -------- -------- -------- -------- ---------------- 180480 50224 46690 0 3548 0 46676 0 0 [anon:scudo:primary]
dumpsys meminfoSee the official dumpsys meminfo documentation for more details.
For a quick summarized view of process memory usage, dumpsys meminfo is a useful tool that aggregates memory usage into logical buckets and types. The -d argument enables more granular details on ART-specific memory usage. As an example, an abbreviated view for system_server (using adb shell dumpsys meminfo -d system_server) might look like:
Pss Private Private Swap Rss Total Dirty Clean Dirty Total ------ ------ ------ ------ ------ Native Heap 51005 50988 0 0 55460 Dalvik Heap 75478 75428 0 0 83340 Dalvik Other 13020 12300 0 0 14176 ... .so mmap 29999 2344 17540 0 116256 # Native libraries .jar mmap 50250 0 19348 0 177644 # Boot classpath or system JARs (DEX) .apk mmap 89373 0 51412 0 148888 # APK resources + code .dex mmap 18945 148 13988 0 25408 # Extracted or mapped DEX .oat mmap 1220 0 460 0 26092 # AOT Code .art mmap 3399 3180 20 0 34100 # Boot/App Images ... TOTAL 391182 191124 110416 0 750724
The next section gives a more granular breakdown of ART memory usage by mapping region:
Dalvik Details .Heap 74084 74084 0 0 74084 # 100% dirty! .LOS 638 628 0 0 2256 # Primitive array allocs > 12KB. .Zygote 456 416 0 0 6700 # Zygote space .NonMoving 300 300 0 0 300 # Internal non-movable data structures .LinearAlloc 9700 9700 0 0 9700 # Class/Method metadata .GC 2564 2564 0 0 3000 # Overhead for GC .AppJIT 720 0 0 0 1440 # JIT cache + data .IndirectRef 36 36 0 0 36 # Includes JNI references .Boot vdex 585 0 428 0 2156 # Clean! .App dex 17768 148 13520 0 22100 # Mostly clean! .App vdex 592 0 40 0 1152 # Clean! .App art 368 364 4 0 368 # Mostly dirty! .Boot art 3031 2816 16 0 33732 # Mostly dirty!
Finally, we get a summary of overall memory usage for the process:
App Summary Pss(KB) Rss(KB) ------ ------ Java Heap: 78628 117440 # [anon:dalvik-main/zygote/etc] Native Heap: 50988 55460 # [anon:scudo/malloc] Code: 105300 496164 # .so + .jar + .apk + .dex + .oat + .art .... Private Other: 21816 # LinearAlloc, indirect ref, etc. .... TOTAL PSS: 391182 TOTAL RSS: 750724
dexdump: A (host/device) tool for inspecting and analyzing DEX and JAR files. It provides detailed info on classes, methods, and bytecode.oatdump: A (host/device) tool for analyzing OAT and ODEX files, providing a view into the compiled native code and metadata. See the companion disassembly guide for more details.apkanalyzer: A (host) tool for analyzing APKs, including resource size, DEX contents, and manifest details.dumpsys package dexopt: A (device) command providing details on the compilation state for installed apps.