点赞关注,不再迷路,你的支持对我意义重大!
🔥 Hi,我是丑丑。本文 「Android 路线」| 导读 —— 从零到无穷大 已收录,这里有 Android 进阶成长路线笔记 & 博客,欢迎跟着彭丑丑一起成长。(联系方式在 GitHub)
目录
前置知识
这篇文章的内容会涉及以下前置 / 相关知识,贴心的我都帮你准备好了,请享用~
- 程序执行: Android 虚拟机 | 从类加载到程序执行
1. 内存指标
在讨论具体的内存优化方法之前,我们先来讨论内存的指标与分析工具。首先你需要理解这些内存指标
1.1 最大堆内存
为了避免应用滥用内存,Android 系统会限制应用可以申请的最大堆内存,超过此限制就会抛出 OOM 异常。Android 设备出厂后,最大堆内存就已经确定,相关的配置位于系统根目录/system/build.prop
文件中,我们可以通过命令查看:
命令:
adb shell cat /system/build.prop
------------------------------------------------------------------
输出:
...
dalvik.vm.heapstartsize=16m [进程启动的初始堆内存]
dalvik.vm.heapgrowthlimit=128m [进程最大堆内存]
dalvik.vm.heapsize=192m [进程最大堆内存(开启 largeHeap="true")]
dalvik.vm.heaptargetutilization=0.75
dalvik.vm.heapminfree=512k
dalvik.vm.heapmaxfree=8m
...
虚拟机参数 | 描述 |
---|---|
dalvik.vm.heapstartsize | 进程启动的初始堆内存 |
dalvik.vm.heapgrowthlimit | 进程最大堆内存 |
dalvik.vm.heapsize | 进程最大堆内存(开启 largeHeap="true") |
dalvik.vm.heaptargetutilization | |
dalvik.vm.heapminfree | |
dalvik.vm.heapmaxfree |
在 App 虚拟机启动时,会读取/system/build.prop
文件的配置,源码位于:AndroidRuntime.cpp
->虚拟机启动
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote) {
...
parseRuntimeOption("dalvik.vm.heapstartsize", heapstartsizeOptsBuf, "-Xms", "4m");
parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m");
parseRuntimeOption("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit=");
parseRuntimeOption("dalvik.vm.heapminfree", heapminfreeOptsBuf, "-XX:HeapMinFree=");
parseRuntimeOption("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf, "-XX:HeapMaxFree=");
parseRuntimeOption("dalvik.vm.heaptargetutilization", heaptargetutilizationOptsBuf, "-XX:HeapTargetUtilization=");
...
}
需要注意的是,配置dalvik.vm.heapgrowthlimit
限制的仅仅是 Java 堆内存,本地内存时不受其限制的。换句话说,应用可以使用的最大内存其实是可以大于最大堆内存的。
1.2 进程到底占用了多少内存?
在 Linux 里,一个进程占用的内存有四种指标,分别是:
内存指标 | 全称 | 关系 |
---|---|---|
VSS | Virtual Set Size | 一个进程可访问的地址空间 |
RSS | Resident Set Size | 一个进程实际占用的内存大小(包含共享库占用的内存) |
PSS | Proportional Set Size | 一个进程实际占用的内存大小(按比例计算共享库占用的内存) |
USS | Unique Set Size | 进程独立占用的物理内存(不包含共享库占用的内存) |
一般来说内存占用大小有如下规律:VSS >= RSS >= PSS >= USS。
VSS: 一个进程可访问的地址空间,其大小还包括分配但未使用的内存,因此对于分析进程占用内存用处不大;
RSS: 一个进程实际占用的内存大小,RSS 同样也不太准确,主要是因为 RSS 还包括该进程使用的共享库。而一个共享库是可以被多个进程共享的,以至于所有进程的 RSS 相加会超过物理内存很多;
PSS: 一个进程实际占用的内存大小,相对于 RSS,它是按照比例计算共享库占用的内存的。例如一个共享库被 N 个进程共享,那么 PSS 只会计算 共享库内存。PSS 在有些时候也是有偏差的,例如进程 A 和进程 B 使用同一个共享库没并且 B 在 A 之后启动,那么在 B 启动的那一刻,A 的 PSS 会突然断崖式降低,即时 A 并没有做任何内存释放,这会给分析进程内存行为带来麻烦。
USS: 一个进程占用的私有内存大小,相对于其它指标,USS 不包含共享库占用的内存,只包含进程独占的内存部分。如果该进程终止,USS 就是实际被返还给系统的内存大小。
—— 图片引用自 https://www.cnblogs.com/sunsky303/p/13494977.html —— sunsky303 著
2. 内存分析命令
Applications Memory Usage (in Kilobytes):
Uptime: 11344873 Realtime: 11344873
Total PSS by process:
85,517K: cn.kidyn.qdmedical160 (pid 4273 / activities)
67,985K: system (pid 1639)
60,472K: com.android.systemui (pid 1777 / activities)
58,943K: org.chromium.webview_shell (pid 3990 / activities)
29,429K: com.android.launcher3 (pid 2331 / activities)
24,383K: cn.kidyn.qdmedical160:pushservice (pid 4466)
21,077K: com.android.inputmethod.latin (pid 1744)
20,671K: com.android.phone (pid 1878)
20,603K: zygote (pid 1313)
14,790K: cn.kidyn.qdmedical160:core (pid 4320)
14,114K: cn.kidyn.qdmedical160:todaystep (pid 5236)
11,734K: android.process.acore (pid 2422)
10,912K: com.android.packageinstaller (pid 3718)
10,824K: com.android.quicksearchbox (pid 2386 / activities)
6,597K: logd (pid 1256)
6,249K: com.android.calendar (pid 5161)
6,179K: com.android.deskclock (pid 2093)
6,084K: libweexjsb.so (pid 5286)
6,080K: libweexjsb.so (pid 4516)
6,076K: libweexjsb.so (pid 4406)
6,068K: libweexjsb.so (pid 4399)
5,361K: com.android.gallery3d (pid 2539)
5,247K: com.android.providers.calendar (pid 5173)
3,999K: com.android.printspooler (pid 2285)
3,848K: com.android.defcontainer (pid 2752)
3,817K: android.ext.services (pid 2176)
3,811K: audioserver (pid 1314)
3,739K: mediaserver (pid 1322)
3,365K: com.svox.pico (pid 2781)
3,117K: media.extractor (pid 1321)
2,591K: media.codec (pid 1319)
2,533K: cameraserver (pid 1315)
1,930K: surfaceflinger (pid 1308)
1,907K: mediadrmserver (pid 1320)
1,583K: wpa_supplicant (pid 1894)
1,549K: netd (pid 1323)
1,446K: vold (pid 1265)
1,319K: drmserver (pid 1316)
1,253K: sdcard (pid 1789)
1,241K: sdcard (pid 1860)
1,085K: /init (pid 1)
1,074K: hostapd (pid 1596)
1,045K: adbd (pid 1342)
927K: keystore (pid 1318)
718K: rild (pid 1324)
698K: fingerprintd (pid 1326)
681K: installd (pid 1317)
667K: gatekeeperd (pid 1327)
635K: lmkd (pid 1306)
572K: ueventd (pid 930)
551K: logcat (pid 1312)
520K: healthd (pid 1303)
493K: dumpsys (pid 5583)
483K: dnsmasq (pid 1599)
482K: servicemanager (pid 1307)
470K: sh (pid 1311)
442K: sh (pid 1518)
435K: perfprofd (pid 1333)
324K: ipv6proxy (pid 1569)
277K: debuggerd (pid 1264)
239K: debuggerd:signaller (pid 1267)
Total PSS by OOM adjustment:
92,345K: Native
20,603K: zygote (pid 1313)
6,597K: logd (pid 1256)
6,084K: libweexjsb.so (pid 5286)
6,080K: libweexjsb.so (pid 4516)
6,076K: libweexjsb.so (pid 4406)
6,068K: libweexjsb.so (pid 4399)
3,811K: audioserver (pid 1314)
3,739K: mediaserver (pid 1322)
3,117K: media.extractor (pid 1321)
2,591K: media.codec (pid 1319)
2,533K: cameraserver (pid 1315)
1,930K: surfaceflinger (pid 1308)
1,907K: mediadrmserver (pid 1320)
1,583K: wpa_supplicant (pid 1894)
1,549K: netd (pid 1323)
1,446K: vold (pid 1265)
1,319K: drmserver (pid 1316)
1,253K: sdcard (pid 1789)
1,241K: sdcard (pid 1860)
1,085K: /init (pid 1)
1,074K: hostapd (pid 1596)
1,045K: adbd (pid 1342)
927K: keystore (pid 1318)
718K: rild (pid 1324)
698K: fingerprintd (pid 1326)
681K: installd (pid 1317)
667K: gatekeeperd (pid 1327)
635K: lmkd (pid 1306)
572K: ueventd (pid 930)
551K: logcat (pid 1312)
520K: healthd (pid 1303)
493K: dumpsys (pid 5583)
483K: dnsmasq (pid 1599)
482K: servicemanager (pid 1307)
470K: sh (pid 1311)
442K: sh (pid 1518)
435K: perfprofd (pid 1333)
324K: ipv6proxy (pid 1569)
277K: debuggerd (pid 1264)
239K: debuggerd:signaller (pid 1267)
67,985K: System
67,985K: system (pid 1639)
81,143K: Persistent
60,472K: com.android.systemui (pid 1777 / activities)
20,671K: com.android.phone (pid 1878)
29,429K: Foreground
29,429K: com.android.launcher3 (pid 2331 / activities)
39,684K: Visible
21,077K: com.android.inputmethod.latin (pid 1744)
14,790K: cn.kidyn.qdmedical160:core (pid 4320)
3,817K: android.ext.services (pid 2176)
14,114K: A Services
14,114K: cn.kidyn.qdmedical160:todaystep (pid 5236)
90,764K: Previous
85,517K: cn.kidyn.qdmedical160 (pid 4273 / activities)
5,247K: com.android.providers.calendar (pid 5173)
24,383K: B Services
24,383K: cn.kidyn.qdmedical160:pushservice (pid 4466)
121,414K: Cached
58,943K: org.chromium.webview_shell (pid 3990 / activities)
11,734K: android.process.acore (pid 2422)
10,912K: com.android.packageinstaller (pid 3718)
10,824K: com.android.quicksearchbox (pid 2386 / activities)
6,249K: com.android.calendar (pid 5161)
6,179K: com.android.deskclock (pid 2093)
5,361K: com.android.gallery3d (pid 2539)
3,999K: com.android.printspooler (pid 2285)
3,848K: com.android.defcontainer (pid 2752)
3,365K: com.svox.pico (pid 2781)
Total PSS by category:
114,379K: Native
100,052K: Dalvik
64,802K: .dex mmap
54,784K: .so mmap
44,872K: .oat mmap
41,614K: .apk mmap
36,631K: Unknown
32,520K: Ashmem
30,866K: .art mmap
14,411K: Other mmap
14,162K: Dalvik Other
9,460K: Stack
2,019K: .ttf mmap
501K: Other dev
160K: .jar mmap
28K: Cursor
0K: Gfx dev
0K: EGL mtrack
0K: GL mtrack
0K: Other mtrack
Total RAM: 1,550,644K (status normal)
Free RAM: 1,036,918K ( 121,414K cached pss + 499,892K cached kernel + 415,612K free)
Used RAM: 514,515K ( 439,847K used pss + 74,668K kernel)
Lost RAM: -789K
Tuning: 384 (large 384), oom 184,320K, restore limit 61,440K (high-end-gfx)
3. 内存分析工具
参考资料
创作不易,你的「三连」是丑丑最大的动力,我们下次见!