點贊關注,不再迷路,你的支持對我意義重大!
🔥 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. 內存分析工具
參考資料
創作不易,你的「三連」是醜醜最大的動力,我們下次見!