如何分析Android应用.apk mmap内存占用并降低其消耗
问题
分析Android应用内存使用时,发现启动阶段.apk mmap区域占用大量内存。执行adb shell dumpsys com.testapp.foo得到以下内存信息:
adb shell dumpsys com.testapp.foo Applications Memory Usage (in Kilobytes): Uptime: 3367859 Realtime: 3367859 ** MEMINFO in pid 5286 [com.testapp.foo] ** Pss Private Private Swap Rss Heap Heap Heap Total Dirty Clean Dirty Total Size Alloc Free ------ ------ ------ ------ ------ ------ ------ ------ Native Heap 5256 5160 0 0 8436 13524 7183 2379 Dalvik Heap 8282 7996 0 0 16504 16771 8386 8385 Dalvik Other 7534 7480 0 0 9992 Stack 1356 1356 0 0 1368 Ashmem 17 0 0 0 536 Other dev 16 0 16 0 304 .so mmap 917 168 0 0 23464 .jar mmap 1207 0 0 0 27964 .apk mmap 64405 640 63400 0 65424 .dex mmap 28 8 0 0 616 .oat mmap 524 0 0 0 11940 .art mmap 1300 644 0 0 19652 Other mmap 195 40 96 0 1648 Unknown 549 532 0 0 1376 TOTAL 91586 24024 63512 0 189224 30295 15569 10764
可见.apk mmap占用超过60MB,尝试adb shell cat /proc/<pid>/smaps无法获取足够详细的消耗信息,需要了解分析.apk mmap使用情况的方法,以及降低其内存消耗的方案。
分析.apk mmap内存的方法
- 使用
adb shell procmem <pid>命令:该命令能更细致地拆分进程的内存映射,包括.apk文件内各个段(如资源、代码、assets等)的内存占用,相比smaps更直观展示.apk相关的内存分配。 - 借助Android Studio Profiler的内存快照:在Profiler中捕获内存快照后,查看"Memory Map"标签,筛选
.apk相关的映射条目,可看到具体的文件路径和占用大小,还能关联到对应的资源或代码模块。 - 解析
/proc/<pid>/maps结合apktool反编译:先通过adb shell cat /proc/<pid>/maps获取.apk的内存映射起始结束地址,再用apktool反编译apk,分析对应地址范围内的文件内容(比如大资源文件、未压缩的assets),定位具体是哪些部分占用内存。
降低.apk mmap内存消耗的优化方案
- 优化资源文件:
- 压缩PNG/JPG图片,使用WebP或AVIF格式替代,减少图片资源的体积;移除未使用的资源(通过Android Studio的"Remove Unused Resources"工具)。
- 对于大尺寸的assets文件(如离线数据包、音频),考虑拆分或按需加载,避免启动时一次性映射整个文件到内存。
- 启用APK压缩与优化:
- 在
build.gradle中开启android.enableR8=true进行代码混淆与压缩,减少DEX和资源的体积;启用android.bundle.enableUncompressedNativeLibs=false让系统自动压缩Native库。 - 使用App Bundle发布,按需下载模块资源,避免将所有模块的资源打包进一个apk,减少启动时映射的内存大小。
- 在
- 调整内存映射策略:
- 对于非立即需要的资源,采用延迟加载方式,在使用时再进行内存映射,而不是启动阶段全部加载。
- 对于只读资源(如图片、assets),确保系统能共享内存页,避免进程间重复映射相同资源(比如避免私自修改只读资源导致内存页变脏)。
- 检查APK结构:
- 移除apk中冗余的文件(如重复的资源、测试用文件);检查是否有大的未压缩文件(如某些二进制文件未被压缩),对其进行压缩处理。
内容的提问来源于stack exchange,提问作者Jian Guo
相关产品推荐
相关产品推荐

