dumpsys
?是一種在 Android 設備上運行的工具,可提供有關系統服務的信息。可以使用?Android 調試橋 (adb)?從命令行調用?dumpsys
,獲取在連接的設備上運行的所有系統服務的診斷輸出。
此輸出通常比您想要的更詳細,因此請使用此頁面上的命令行選項僅獲取您所需的系統服務的輸出。本頁還介紹了如何使用?dumpsys
?完成常見的任務,如檢查輸入、RAM、電池或網絡診斷信息。
語法
使用?dumpsys
?的一般語法如下:
adb shell dumpsys [-t timeout] [--help | -l | --skip services | service [arguments] | -c | -h]
如需獲取所連接設備的所有系統服務的診斷輸出,請運行?adb shell dumpsys
。不過,這樣輸出的信息比您通常想要的信息多得多。若要使輸出更加可控,您可以通過在命令中添加相應服務來指定要檢查的服務。例如,下面的命令會提供輸入組件(如觸摸屏或內置鍵盤)的系統數據:
adb shell dumpsys input
如需查看可與?dumpsys
?配合使用的系統服務的完整列表,請使用以下命令:
adb shell dumpsys -l
命令行選項
下表列出了使用?dumpsys
?時的可用選項:
表 1.?dumpsys 的可用選項列表
選項 | 說明 |
---|---|
-t?timeout | 指定超時期限(秒)。如果未指定,默認值為 10 秒。 |
--help | 輸出?dumpsys ?工具的幫助文本。 |
-l | 輸出可與?dumpsys ?配合使用的系統服務的完整列表。 |
--skip?services | 指定您不希望包含在輸出中的?services。 |
service?[arguments] | 指定您希望輸出的?service。某些服務可能允許您傳遞可選?arguments。要了解 這些可選實參,請將?-h ?選項與 服務: adb shell dumpsys procstats -h |
-c | 指定某些服務時,附加此選項能以計算機可讀的格式輸出數據。 |
-h | 對于某些服務,附加此選項可查看該服務的幫助文本和其他選項。 |
檢查輸入診斷
指定?input
?服務(如以下命令所示)可轉儲系統輸入設備(如鍵盤和觸摸屏)的狀態以及輸入事件的處理。
adb shell dumpsys input
輸出內容因連接的設備上搭載的 Android 版本不同而異。以下部分介紹您通常會看到的信息類型。
Event Hub 狀態
以下是您在檢查輸入診斷信息的?Event Hub 狀態時可能會看到的信息示例:
INPUT MANAGER (dumpsys input)Event Hub State:BuiltInKeyboardId: -2Devices:-1: VirtualClasses: 0x40000023Path: Descriptor: a718a782d34bc767f4689c232d64d527998ea7fdLocation:ControllerNumber: 0UniqueId: Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000KeyLayoutFile: /system/usr/keylayout/Generic.klKeyCharacterMapFile: /system/usr/keychars/Virtual.kcmConfigurationFile:HaveKeyboardLayoutOverlay: false1: msm8974-taiko-mtp-snd-card Headset JackClasses: 0x00000080Path: /dev/input/event5Descriptor: c8e3782483b4837ead6602e20483c46ff801112cLocation: ALSAControllerNumber: 0UniqueId:Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000KeyLayoutFile:KeyCharacterMapFile:ConfigurationFile:HaveKeyboardLayoutOverlay: false2: msm8974-taiko-mtp-snd-card Button JackClasses: 0x00000001Path: /dev/input/event4Descriptor: 96fe62b244c555351ec576b282232e787fb42babLocation: ALSAControllerNumber: 0UniqueId:Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000KeyLayoutFile: /system/usr/keylayout/msm8974-taiko-mtp-snd-card_Button_Jack.klKeyCharacterMapFile: /system/usr/keychars/msm8974-taiko-mtp-snd-card_Button_Jack.kcmConfigurationFile:HaveKeyboardLayoutOverlay: false3: hs_detectClasses: 0x00000081Path: /dev/input/event3Descriptor: 485d69228e24f5e46da1598745890b214130dbc4Location:ControllerNumber: 0UniqueId:Identifier: bus=0x0000, vendor=0x0001, product=0x0001, version=0x0001KeyLayoutFile: /system/usr/keylayout/hs_detect.klKeyCharacterMapFile: /system/usr/keychars/hs_detect.kcmConfigurationFile:HaveKeyboardLayoutOverlay: false ...
Input Reader 狀態
InputReader
?負責對來自內核的輸入事件進行解碼。其狀態轉儲會顯示各輸入設備的配置信息以及最近發生的狀態變化,如按下按鍵或輕觸觸摸屏等操作。
以下示例顯示了觸摸屏的輸出。注意有關設備分辨率和所用校準參數的信息。
Input Reader State ...Device 6: Melfas MMSxxx TouchscreenIsExternal: falseSources: 0x00001002KeyboardType: 0Motion Ranges:X: source=0x00001002, min=0.000, max=719.001, flat=0.000, fuzz=0.999Y: source=0x00001002, min=0.000, max=1279.001, flat=0.000, fuzz=0.999PRESSURE: source=0x00001002, min=0.000, max=1.000, flat=0.000, fuzz=0.000SIZE: source=0x00001002, min=0.000, max=1.000, flat=0.000, fuzz=0.000TOUCH_MAJOR: source=0x00001002, min=0.000, max=1468.605, flat=0.000, fuzz=0.000TOUCH_MINOR: source=0x00001002, min=0.000, max=1468.605, flat=0.000, fuzz=0.000TOOL_MAJOR: source=0x00001002, min=0.000, max=1468.605, flat=0.000, fuzz=0.000TOOL_MINOR: source=0x00001002, min=0.000, max=1468.605, flat=0.000, fuzz=0.000Touch Input Mapper:Parameters:GestureMode: spotsDeviceType: touchScreenAssociatedDisplay: id=0, isExternal=falseOrientationAware: trueRaw Touch Axes:X: min=0, max=720, flat=0, fuzz=0, resolution=0Y: min=0, max=1280, flat=0, fuzz=0, resolution=0Pressure: min=0, max=255, flat=0, fuzz=0, resolution=0TouchMajor: min=0, max=30, flat=0, fuzz=0, resolution=0TouchMinor: unknown rangeToolMajor: unknown rangeToolMinor: unknown rangeOrientation: unknown rangeDistance: unknown rangeTiltX: unknown rangeTiltY: unknown rangeTrackingId: min=0, max=65535, flat=0, fuzz=0, resolution=0Slot: min=0, max=9, flat=0, fuzz=0, resolution=0Calibration:touch.size.calibration: diametertouch.size.scale: 10.000touch.size.bias: 0.000touch.size.isSummed: falsetouch.pressure.calibration: amplitudetouch.pressure.scale: 0.005touch.orientation.calibration: nonetouch.distance.calibration: noneSurfaceWidth: 720pxSurfaceHeight: 1280pxSurfaceOrientation: 0Translation and Scaling Factors:XScale: 0.999YScale: 0.999XPrecision: 1.001YPrecision: 1.001GeometricScale: 0.999PressureScale: 0.005SizeScale: 0.033OrientationCenter: 0.000OrientationScale: 0.000DistanceScale: 0.000HaveTilt: falseTiltXCenter: 0.000TiltXScale: 0.000TiltYCenter: 0.000TiltYScale: 0.000Last Button State: 0x00000000Last Raw Touch: pointerCount=0Last Cooked Touch: pointerCount=0
在 Input Reader 狀態轉儲的結尾部分,會顯示一些關于全局配置參數的信息,例如點按時間間隔:
Configuration: ExcludedDeviceNames: [] VirtualKeyQuietTime: 0.0ms PointerVelocityControlParameters: scale=1.000, lowThreshold=500.000, highThreshold=3000.000, acceleration=3.000 WheelVelocityControlParameters: scale=1.000, lowThreshold=15.000, highThreshold=50.000, acceleration=4.000 PointerGesture: Enabled: true QuietInterval: 100.0ms DragMinSwitchSpeed: 50.0px/s TapInterval: 150.0ms TapDragInterval: 300.0ms TapSlop: 20.0px MultitouchSettleInterval: 100.0ms MultitouchMinDistance: 15.0px SwipeTransitionAngleCosine: 0.3 SwipeMaxWidthRatio: 0.2 MovementSpeedRatio: 0.8 ZoomSpeedRatio: 0.3
Input Dispatcher 狀態
InputDispatcher
?負責向應用發送輸入事件。如以下示例輸出所示,其狀態轉儲顯示許多方面的信息,包括正在輕觸哪個窗口、輸入隊列的狀態、是否正在進行 ANR 以及其他輸入事件信息:
Input Dispatcher State:DispatchEnabled: 1DispatchFrozen: 0FocusedApplication: <null>FocusedWindow: name='Window{3fb06dc3 u0 StatusBar}'TouchStates: <no displays touched>Windows:0: name='Window{357bbbfe u0 SearchPanel}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=false, canReceiveKeys=false, flags=0x01820100, type=0x000007e8, layer=211000, frame=[0,0][1080,1920], scale=1.000000, touchableRegion=[0,0][1080,1920], inputFeatures=0x00000000, ownerPid=22674, ownerUid=10020, dispatchingTimeout=5000.000ms1: name='Window{3b14c0ca u0 NavigationBar}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=false, canReceiveKeys=false, flags=0x01840068, type=0x000007e3, layer=201000, frame=[0,1776][1080,1920], scale=1.000000, touchableRegion=[0,1776][1080,1920], inputFeatures=0x00000000, ownerPid=22674, ownerUid=10020, dispatchingTimeout=5000.000ms2: name='Window{2c7e849c u0 com.vito.lux}', displayId=0, paused=false, hasFocus=false, hasWallpaper=false, visible=true, canReceiveKeys=false, flags=0x0089031a, type=0x000007d6, layer=191000, frame=[-495,-147][1575,1923], scale=1.000000, touchableRegion=[-495,-147][1575,1923], inputFeatures=0x00000000, ownerPid=4697, ownerUid=10084, dispatchingTimeout=5000.000ms...MonitoringChannels:0: 'WindowManager (server)'RecentQueue: length=10MotionEvent(deviceId=4, source=0x00001002, action=2, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, edgeFlags=0x00000000, xPrecision=1.0, yPrecision=1.0, displayId=0, pointers=[0: (335.0, 1465.0)]), policyFlags=0x62000000, age=217264.0msMotionEvent(deviceId=4, source=0x00001002, action=1, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, edgeFlags=0x00000000, xPrecision=1.0, yPrecision=1.0, displayId=0, pointers=[0: (335.0, 1465.0)]), policyFlags=0x62000000, age=217255.7msMotionEvent(deviceId=4, source=0x00001002, action=0, flags=0x00000000, metaState=0x00000000, buttonState=0x00000000, edgeFlags=0x00000000, xPrecision=1.0, yPrecision=1.0, displayId=0, pointers=[0: (330.0, 1283.0)]), policyFlags=0x62000000, age=216805.0ms...PendingEvent: <none>InboundQueue: <empty>ReplacedKeys: <empty>Connections:0: channelName='WindowManager (server)', windowName='monitor', status=NORMAL, monitor=true, inputPublisherBlocked=falseOutboundQueue: <empty>WaitQueue: <empty>1: channelName='278c1d65 KeyguardScrim (server)', windowName='Window{278c1d65 u0 KeyguardScrim}', status=NORMAL, monitor=false, inputPublisherBlocked=falseOutboundQueue: <empty>WaitQueue: <empty>2: channelName='357bbbfe SearchPanel (server)', windowName='Window{357bbbfe u0 SearchPanel}', status=NORMAL, monitor=false, inputPublisherBlocked=falseOutboundQueue: <empty>WaitQueue: <empty>...AppSwitch: not pending7: channelName='2280455f com.google.android.gm/com.google.android.gm.ConversationListActivityGmail (server)', windowName='Window{2280455f u0 com.google.android.gm/com.google.android.gm.ConversationListActivityGmail}', status=NORMAL, monitor=false, inputPublisherBlocked=falseOutboundQueue: <empty>WaitQueue: <empty>8: channelName='1a7be08a com.android.systemui/com.android.systemui.recents.RecentsActivity (server)', windowName='Window{1a7be08a u0 com.android.systemui/com.android.systemui.recents.RecentsActivity EXITING}', status=NORMAL, monitor=false, inputPublisherBlocked=falseOutboundQueue: <empty>WaitQueue: <empty>9: channelName='3b14c0ca NavigationBar (server)', windowName='Window{3b14c0ca u0 NavigationBar}', status=NORMAL, monitor=false, inputPublisherBlocked=falseOutboundQueue: <empty>WaitQueue: <empty>...Configuration:KeyRepeatDelay: 50.0msKeyRepeatTimeout: 500.0ms
檢查事項
下面列出了在檢查?input
?服務的輸出時要考慮的事項:
Event Hub 狀態:
- 所有預期的輸入設備是否都存在。
- 每個輸入設備是否都有適當的按鍵布局文件、按鍵字符映射文件和輸入設備配置文件。如果這些文件缺失或包含語法錯誤,則無法加載它們。
- 每個輸入設備是否都已正確分類。
Classes
?字段中的位是否對應于?EventHub.h
?中的標志,如?INPUT_DEVICE_CLASS_TOUCH_MT
。 BuiltInKeyboardId
?是否正確無誤。如果設備未配備內置鍵盤,則該 ID 必須為?-2
。否則,應為內置鍵盤的 ID。- 如果您發現?
BuiltInKeyboardId
?應該為?-2
,但卻不是,則說明缺少某個特殊功能小鍵盤的按鍵字符映射文件。特殊功能小鍵盤設備應具有僅包含?type SPECIAL_FUNCTION
?行的按鍵字符映射文件。
- 如果您發現?
Input Reader 狀態:
- 所有的預期輸入設備是否都存在。
- 每個輸入設備是否都已配置正確。特別注意檢查觸摸屏和操縱桿軸是否正確。
Input Dispatcher 狀態:
- 所有輸入事件是否均按預期進行處理。
- 輕觸觸摸屏的同時運行?
dumpsys
?后,TouchStates
?行是否正確標識了您所輕觸的窗口。
測試界面性能
如果指定?gfxinfo
?服務,輸出中會包含錄制階段所發生的動畫幀的相關性能信息。 以下命令使用?gfxinfo
?收集指定軟件包名稱的界面性能數據:
adb shell dumpsys gfxinfo package-name
您還可以包含?framestats
?選項,以提供有關最近發生的幀的更加詳細的幀時間信息,讓您能夠更準確地找到問題并進行調試:
adb shell dumpsys gfxinfo package-name framestats
如需詳細了解如何使用?gfxinfo
?和?framestats
?將界面性能測量值集成到測試實踐中,請參閱編寫 Macrobenchmark。
檢查網絡診斷信息
指定?netstats
?服務可提供自設備上次啟動以來收集的網絡使用情況統計信息。若要輸出額外信息,如詳細的唯一用戶 ID (UID) 信息,請包含?detail
?選項,如下所示:
adb shell dumpsys netstats detail
輸出內容因連接的設備上搭載的 Android 版本不同而異。以下部分介紹您通常會看到的信息類型。
活動接口和活動 UID 接口
以下示例輸出內容中列出了連接的設備的活躍接口和活躍 UID 接口。在大多數情況下,活躍接口和活躍 UID 接口的信息是相同的。
Active interfaces: iface=wlan0 ident=[{type=WIFI, subType=COMBINED, networkId="Guest"}] Active UID interfaces: iface=wlan0 ident=[{type=WIFI, subType=COMBINED, networkId="Guest"}]
“Dev”和“Xt”統計信息
以下是 Dev 統計信息部分的示例輸出:
Dev stats: Pending bytes: 1798112 History since boot: ident=[{type=WIFI, subType=COMBINED, networkId="Guest", metered=false}] uid=-1 set=ALL tag=0x0 NetworkStatsHistory: bucketDuration=3600 st=1497891600 rb=1220280 rp=1573 tb=309870 tp=1271 op=0 st=1497895200 rb=29733 rp=145 tb=85354 tp=185 op=0 st=1497898800 rb=46784 rp=162 tb=42531 tp=192 op=0 st=1497902400 rb=27570 rp=111 tb=35990 tp=121 op=0 Xt stats: Pending bytes: 1771782 History since boot: ident=[{type=WIFI, subType=COMBINED, networkId="Guest", metered=false}] uid=-1 set=ALL tag=0x0 NetworkStatsHistory: bucketDuration=3600 st=1497891600 rb=1219598 rp=1557 tb=291628 tp=1255 op=0 st=1497895200 rb=29623 rp=142 tb=82699 tp=182 op=0 st=1497898800 rb=46684 rp=160 tb=39756 tp=191 op=0 st=1497902400 rb=27528 rp=110 tb=34266 tp=120 op=0
UID 統計信息
以下是每個 UID 的詳細統計信息的示例:
UID stats: Pending bytes: 744 Complete history: ident=[[type=MOBILE_SUPL, subType=COMBINED, subscriberId=311111...], [type=MOBILE, subType=COMBINED, subscriberId=311111...]] uid=10007 set=DEFAULT tag=0x0 NetworkStatsHistory: bucketDuration=7200000 bucketStart=1406167200000 activeTime=7200000 rxBytes=4666 rxPackets=7 txBytes=1597 txPackets=10 operations=0 ident=[[type=WIFI, subType=COMBINED, networkId="MySSID"]] uid=10007 set=DEFAULT tag=0x0 NetworkStatsHistory: bucketDuration=7200000 bucketStart=1406138400000 activeTime=7200000 rxBytes=17086802 rxPackets=15387 txBytes=1214969 txPackets=8036 operations=28 bucketStart=1406145600000 activeTime=7200000 rxBytes=2396424 rxPackets=2946 txBytes=464372 txPackets=2609 operations=70 bucketStart=1406152800000 activeTime=7200000 rxBytes=200907 rxPackets=606 txBytes=187418 txPackets=739 operations=0 bucketStart=1406160000000 activeTime=7200000 rxBytes=826017 rxPackets=1126 txBytes=267342 txPackets=1175 operations=35
如需查找應用的 UID,請運行以下命令:adb shell dumpsys package?your-package-name
。然后查找標有?userId
?的行。
例如,如需查找應用“com.example.myapp”的網絡使用情況,請運行以下命令:
adb shell dumpsys package com.example.myapp | grep userId
輸出的內容應類似于以下文本:
userId=10007 gids=[3003, 1028, 1015]
使用上述示例轉儲,查找包含?uid=10007
?的行。有兩個這樣的行,第一個表示移動數據連接,第二個表示 Wi-Fi 連接。在每一行下方,您可以看到每個兩小時期限(bucketDuration
?以毫秒為單位表示)的以下信息:
set=DEFAULT
?表示前臺網絡使用情況,set=BACKGROUND
?表示后臺網絡使用情況,set=ALL
?表示這兩種網絡使用情況。tag=0x0
?表示與流量關聯的套接字標簽。rxBytes
?和?rxPackets
?表示在相應時間間隔內接收的字節數和數據包數。txBytes
?和?txPackets
?表示在相應時間間隔內發送(傳輸)的字節數和數據包數。
檢查電池診斷信息
指定?batterystats
?服務會生成關于設備電池用量的統計數據,這些數據按唯一用戶 ID (UID) 進行整理。如需了解如何使用?dumpsys
?在低電耗模式和應用待機模式下測試應用,請參閱在低電耗模式和應用待機模式下進行測試。
batterystats
?的命令如下所示:
adb shell dumpsys batterystats options
如需查看?batterystats
?可用的其他選項列表,請添加?-h
?選項。以下示例會輸出自設備上次充電以來指定應用軟件包的電池用量統計信息:
adb shell dumpsys batterystats --charged package-name
輸出通常包含以下內容:
- 電池相關事件的歷史記錄
- 設備的全局統計信息
- 每個 UID 和系統組件的大致用電量
- 單個應用的每個數據包占用的移動網絡毫秒數
- 系統 UID 匯總統計信息
- 應用 UID 匯總統計信息
如需詳細了解如何使用?batterystats
?以及如何生成 HTML 格式的可視化輸出內容,以便于您理解和診斷電池相關問題,請參閱使用 Batterystats 和 Battery Historian 分析電池用量。
檢查計算機可讀格式的輸出
您可以使用以下命令以計算機可讀的 CSV 格式生成?batterystats
?輸出:
adb shell dumpsys batterystats --checkin
以下是輸出示例:
9,0,i,vers,11,116,K,L 9,0,i,uid,1000,android 9,0,i,uid,1000,com.android.providers.settings 9,0,i,uid,1000,com.android.inputdevices 9,0,i,uid,1000,com.android.server.telecom ... 9,0,i,dsd,1820451,97,s-,p- 9,0,i,dsd,3517481,98,s-,p- 9,0,l,bt,0,8548446,1000983,8566645,1019182,1418672206045,8541652,994188 9,0,l,gn,0,0,666932,495312,0,0,2104,1444 9,0,l,m,6794,0,8548446,8548446,0,0,0,666932,495312,0,697728,0,0,0,5797,0,0 ...
電池用量檢測可以基于 UID 進行,也可以在系統級別進行。是否包含某項數據是根據其對于分析電池性能的作用決定的。每一行代表一項包含以下元素的檢測信息:
- 一個占位符整數
- 與檢測關聯的用戶 ID
- 聚合模式:
i
?表示不與已充電/未充電狀態關聯的信息。l
?表示?--charged
(自上次充電后的使用情況)。u
?表示?--unplugged
(自上次拔下電源后的使用情況)。在 Android 5.1.1 中已廢棄。
- 區段標識符,用于確定如何解譯行中的后續值。
下表介紹了您可能會看到的各種區段標識符:
表 2.?區段標識符列表
區段標識符 | 說明 | 其余字段 |
---|---|---|
| 版本 |
|
| UID |
|
| APK |
|
| 進程 |
|
| 傳感器 |
|
| 振動器 |
|
| 前景 |
|
| 狀態時間 |
|
| 喚醒鎖 |
|
| 同步 |
|
| 作業 |
|
| 內核喚醒鎖定 |
|
| 喚醒原因 |
|
| 網絡 |
|
| 用戶活動 |
|
| 電池 |
|
| 電池電量消耗 |
|
| 電量 |
|
| Wi-Fi |
|
| 全局 Wi-Fi |
|
| 全局藍牙 |
|
| 其他 |
|
| 全局網絡 |
|
| 屏幕亮度 |
|
| 信號掃描時間 |
|
| 信號強度時間 |
|
| 信號強度計數 |
|
| 數據連接時間 |
|
| 數據連接計數 |
|
| Wi-Fi 狀態時間 |
|
| WLAN 狀態計數 |
|
| Wi-Fi 客戶端狀態時間 |
|
| Wi-Fi 客戶端狀態計數 |
|
| Wi-Fi 信號強度時間 |
|
| Wi-Fi 信號強度計數 |
|
| 藍牙狀態時間 |
|
| 藍牙狀態計數 |
|
| 耗電量匯總 |
|
| 耗電項 |
|
| 耗電步驟 |
|
| 充電步驟 |
|
| 耗電剩余時間 |
|
| 充電剩余時間 |
|
注意:對于 Android 6.0 之前的版本,藍牙無線電、移動網絡無線電以及 Wi-Fi 的耗電量在?
m
(“其他”)區段類別中進行跟蹤。在 Android 6.0 及更高版本中,這些組件的耗電量在?pwi
(“耗電項”)區段進行跟蹤,其中每個組件均使用單獨的標簽(wifi
、blue
?和?cell
)。?
查看內存分配情況
您可以通過兩種方法檢查應用的內存占用情況:使用?procstats
?檢查一段時間內的占用情況,或使用?meminfo
?檢查特定時間點的占用情況。 以下幾個部分介紹如何使用這兩種方法。
procstats
procstats
?可以讓您了解應用在一段時間內的表現,包括應用在后臺運行的時長以及在該期間內的內存占用情況。它可以幫助您快速找到應用中的低效環節和不當行為(如內存泄漏),這些問題可能會影響應用的表現,特別是在低內存設備上運行時。其狀態轉儲會顯示有關每個應用的運行時間、按比例分攤的內存大小 (PSS)、獨占內存大小 (USS) 和常駐內存大小 (RSS) 等統計信息。
如需獲取過去三小時內應用的內存占用情況統計信息(采用簡單易懂的格式),請運行以下命令:
adb shell dumpsys procstats --hours 3
如以下示例所示,輸出會顯示應用運行時間的百分比,以及相對樣本數量的 PSS、USS 和 RSS (minPSS-avgPSS-maxPSS/minUSS-avgUSS-maxUSS/minRSS-avgRSS-maxRSS
)。
AGGREGATED OVER LAST 3 HOURS:* com.android.systemui / u0a37 / v28:TOTAL: 100% (15MB-16MB-17MB/7.7MB-8.7MB-9.4MB/7.7MB-9.6MB-84MB over 178)Persistent: 100% (15MB-16MB-17MB/7.7MB-8.7MB-9.4MB/7.7MB-9.6MB-84MB over 178)* com.android.se / 1068 / v28:TOTAL: 100% (2.8MB-2.9MB-2.9MB/300KB-301KB-304KB/304KB-22MB-33MB over 3)Persistent: 100% (2.8MB-2.9MB-2.9MB/300KB-301KB-304KB/304KB-22MB-33MB over 3)* com.google.android.gms.persistent / u0a7 / v19056073:TOTAL: 100% (37MB-38MB-40MB/27MB-28MB-29MB/124MB-125MB-126MB over 2)Imp Fg: 100% (37MB-38MB-40MB/27MB-28MB-29MB/124MB-125MB-126MB over 2)...* com.android.gallery3d / u0a62 / v40030:TOTAL: 0.01%Receiver: 0.01%(Cached): 54% (6.4MB-6.5MB-6.9MB/4.4MB-4.4MB-4.4MB/4.4MB-26MB-68MB over 6)* com.google.android.tvlauncher / u0a30 / v1010900130:TOTAL: 0.01%Receiver: 0.01%(Cached): 91% (5.8MB-13MB-14MB/3.5MB-10MB-12MB/12MB-33MB-78MB over 6)* com.android.vending:instant_app_installer / u0a16 / v81633968:TOTAL: 0.01%Receiver: 0.01%(Cached): 100% (14MB-15MB-16MB/3.8MB-4.2MB-5.1MB/3.8MB-30MB-95MB over 7)... Run time Stats:SOff/Norm: +32m52s226msSOn /Norm: +2h10m8s364msMod : +17s930msTOTAL: +2h43m18s520msMemory usage:Kernel : 265MB (38 samples)Native : 73MB (38 samples)Persist: 262MB (90 samples)Top : 190MB (325 samples)ImpFg : 204MB (569 samples)ImpBg : 754KB (345 samples)Service: 93MB (1912 samples)Receivr: 227KB (1169 samples)Home : 66MB (12 samples)LastAct: 30MB (255 samples)CchAct : 220MB (450 samples)CchCAct: 193MB (71 samples)CchEmty: 182MB (652 samples)Cached : 58MB (38 samples)Free : 60MB (38 samples)TOTAL : 1.9GBServRst: 50KB (278 samples)Start time: 2015-04-08 13:44:18Total elapsed time: +2h43m18s521ms (partial) libart.so
meminfo
您可以使用以下命令記錄應用內存在不同類型的 RAM 分配之間的劃分情況:
adb shell dumpsys meminfo package_name|pid [-d]
-d
?標記會輸出更多與 Dalvik 和 ART 內存占用情況相關的信息。
輸出列出了應用當前的所有分配,以千字節為單位。
檢查此信息時,您應熟悉以下分配類型:
私有(干凈和臟)RAM
這是僅由您的進程使用的內存。這是您的應用進程銷毀后系統可以回收的 RAM 容量。 通常情況下,最重要的部分是私有臟 RAM,它的開銷最大,因為只有您的進程使用它,而且其內容僅存在于 RAM 中,所以無法通過分頁機制映射到硬盤(因為 Android 不使用交換)。您進行的所有 Dalvik 和原生堆分配都將是私有臟 RAM。您與 Zygote 進程共享的 Dalvik 和原生分配則是共享臟 RAM。
實際使用的物理內存(比例分配共享庫占用的內存,PSS)
這是對應用 RAM 占用情況的衡量,考慮了在進程之間共享 RAM 頁的情況。您的進程獨占的 RAM 頁會直接計入其 PSS 值,而與其他進程共享的 RAM 頁則僅會按相應比例計入 PSS 值。例如,兩個進程共享的頁面會占每個進程的 PSS 的一半。
PSS 衡量的一個特點是,您可以將所有進程的 PSS 加起來確定所有進程占用的實際內存。這表示 PSS 是一種理想的方式,可用來衡量進程的實際 RAM 占用比重,以及相對于其他進程和可用的總 RAM 而言,對 RAM 的占用情況。
例如,下面是 Nexus 5 設備上的地圖進程的輸出:
adb shell dumpsys meminfo com.google.android.apps.maps -d
?注意:您看到的信息可能會與此處顯示的內容稍有不同,因為輸出中的某些詳細信息在不同平臺版本上會有所不同。
** MEMINFO in pid 18227 [com.google.android.apps.maps] **Pss Private Private Swapped Heap Heap HeapTotal Dirty Clean Dirty Size Alloc Free------ ------ ------ ------ ------ ------ ------Native Heap 10468 10408 0 0 20480 14462 6017Dalvik Heap 34340 33816 0 0 62436 53883 8553Dalvik Other 972 972 0 0Stack 1144 1144 0 0Gfx dev 35300 35300 0 0Other dev 5 0 4 0.so mmap 1943 504 188 0.apk mmap 598 0 136 0.ttf mmap 134 0 68 0.dex mmap 3908 0 3904 0.oat mmap 1344 0 56 0.art mmap 2037 1784 28 0Other mmap 30 4 0 0EGL mtrack 73072 73072 0 0GL mtrack 51044 51044 0 0Unknown 185 184 0 0TOTAL 216524 208232 4384 0 82916 68345 14570Dalvik Details.Heap 6568 6568 0 0.LOS 24771 24404 0 0.GC 500 500 0 0.JITCache 428 428 0 0.Zygote 1093 936 0 0.NonMoving 1908 1908 0 0.IndirectRef 44 44 0 0ObjectsViews: 90 ViewRootImpl: 1AppContexts: 4 Activities: 1Assets: 2 AssetManagers: 2Local Binders: 21 Proxy Binders: 28Parcel memory: 18 Parcel count: 74Death Recipients: 2 OpenSSL Sockets: 2?
下面是 Gmail 應用的 Dalvik 上一個較舊版本的?dumpsys
:
** MEMINFO in pid 9953 [com.google.android.gm] **Pss Pss Shared Private Shared Private Heap Heap HeapTotal Clean Dirty Dirty Clean Clean Size Alloc Free------ ------ ------ ------ ------ ------ ------ ------ ------Native Heap 0 0 0 0 0 0 7800 7637(6) 126Dalvik Heap 5110(3) 0 4136 4988(3) 0 0 9168 8958(6) 210Dalvik Other 2850 0 2684 2772 0 0Stack 36 0 8 36 0 0Cursor 136 0 0 136 0 0Ashmem 12 0 28 0 0 0Other dev 380 0 24 376 0 4.so mmap 5443(5) 1996 2584 2664(5) 5788 1996(5).apk mmap 235 32 0 0 1252 32.ttf mmap 36 12 0 0 88 12.dex mmap 3019(5) 2148 0 0 8936 2148(5)Other mmap 107 0 8 8 324 68Unknown 6994(4) 0 252 6992(4) 0 0TOTAL 24358(1) 4188 9724 17972(2)16388 4260(2)16968 16595 336ObjectsViews: 426 ViewRootImpl: 3(8)AppContexts: 6(7) Activities: 2(7)Assets: 2 AssetManagers: 2Local Binders: 64 Proxy Binders: 34Death Recipients: 0OpenSSL Sockets: 1SQLMEMORY_USED: 1739PAGECACHE_OVERFLOW: 1164 MALLOC_SIZE: 62?
一般情況下,僅需關注?Pss Total
?和?Private Dirty
?列。 在某些情況下,Private Clean
?和?Heap Alloc
?列提供的數據也值得關注。
下文詳細介紹了您應當關注的不同內存分配:
Dalvik Heap
您應用中的 Dalvik 分配所占用的 RAM。Pss Total
?包括所有 Zygote 分配(如 PSS 定義中所述,通過進程之間共享的內存容量來衡量)。Private Dirty
?值是僅分配給您的應用堆的實際 RAM,包含了您自己的分配和任何 Zygote 分配頁,這些分配頁自從 Zygote 派生您的應用進程以來已被修改。
注意:在包含?Dalvik Other
?區段的更高平臺版本上,Dalvik 堆的?Pss Total
?和?Private Dirty
?數值不包括 Dalvik 開銷(例如即時編譯 (JIT) 和垃圾回收記錄),而更低的版本會在?Dalvik
?中將其一并列出。
Heap Alloc
?是 Dalvik 和原生堆分配器為您的應用記錄的內存占用量。此值大于?Pss Total
?和?Private Dirty
,這是因為您的進程是從 Zygote 派生的,且包含您的進程與所有其他進程共享的分配。
.so mmap?和?.dex mmap
映射的?.so
(原生)和?.dex
(Dalvik 或 ART)代碼占用的 RAM。Pss Total
?值包括應用之間共享的平臺代碼。Private Clean
?是您的應用自己的代碼。通常,實際映射的容量更大。此處的 RAM 只是應用已執行的代碼當前需要占用的 RAM。不過,.so mmap
?具有較大容量的私有臟 RAM,這是因為在將其加載到最終地址時對原生代碼進行了修復。
.oat mmap
這是代碼映像占用的 RAM 容量。它根據由多個應用共用的預加載類計算。此映像在所有應用之間共享,不受特定應用影響。
.art mmap
這是堆映像占用的 RAM 容量。它根據由多個應用共用的預加載類計算。此映像在所有應用之間共享,不受特定應用影響。盡管 ART 映像包含?Object
?實例,但它不會計入您的堆占用空間。
.Heap
(僅帶有?-d
?標志)
這是應用堆所占用的內存容量,其中不包括映像中的對象和大型對象空間,但包括 Zygote 空間和非移動空間。
.LOS(僅帶有?-d?標志)
這是由 ART 大型對象空間占用的 RAM 容量,其中包括 Zygote 大型對象。大型對象是所有大于 12KB 的原語數組分配。
.GC(僅帶有?-d?標志)
這是垃圾回收的開銷成本。無法減少此開銷。
.JITCache(僅帶有?-d?標志)
這是 JIT 數據和代碼緩存占用的內存容量。 通常情況下,此值為零,因為所有應用都是在安裝時編譯的。
.Zygote(僅帶有?-d?標志)
這是 Zygote 空間占用的內存容量。Zygote 空間在設備啟動過程創建且永遠不會被分配。
.NonMoving(僅帶有?-d?標志)
這是由 ART 非移動空間占用的 RAM 容量。非移動空間包含特殊的不可移動對象,例如字段和方法。您可以通過在應用中減少使用字段和方法來減小這部分空間。
.IndirectRef(僅帶有?-d?標志)
這是由 ART 間接引用表占用的 RAM 容量。 通常此容量較小,但如果很高,可以通過減少使用的本地和全局 JNI 引用數量來減小此容量。
Unknown
系統無法將其分類到其他更具體的一個項中的任何 RAM 頁。當前,此類 RAM 頁主要包含原生分配,由于地址空間布局隨機化 (ASLR),工具在收集此數據時無法識別這些分配。與 Dalvik 堆相同,Unknown
?的?Pss Total
?考慮了與 Zygote 共享的容量,且?Private Dirty
?是僅由您的應用占用的未知 RAM。
TOTAL
您的進程占用的按比例分攤的內存大小 (PSS) RAM 總容量,等于上述所有 PSS 字段的總和。該值表示了您的進程占用的內存容量占總體內存容量的比重,可以直接與其他進程和可用的總 RAM 進行比較。
Private Dirty
?和?Private Clean
?合起來就是您進程中的總分配,這些分配未與其他進程共享。 當您的進程被銷毀時,這些分配中的所有 RAM 都會釋放回系統。Private Clean
?也可以在進程銷毀之前被換出和釋放,但?Private Dirty
?僅在進程銷毀后被釋放。
臟 RAM 頁由于已被修改過,因此必須保留在 RAM 中(因為沒有交換)。干凈 RAM 頁是從某個持久性文件(例如正在執行的代碼)映射而來的,因此如果暫時不使用,可以將其換出 RAM。
ViewRootImpl
您的進程中當前處于活動狀態的根視圖數量。每個根視圖都與一個窗口關聯,因此該值有助于您確定與對話框或其他窗口有關的內存泄漏。
AppContexts?和?Activities
您的進程中當前處于活動狀態的應用?Context
?和?Activity
?對象數量。該值可以幫助您快速確定發生泄漏的?Activity
?對象,這些對象由于存在對其的靜態引用(比較常見)而無法進行垃圾回收。這些對象往往關聯了許多其他分配,因此是查找大型內存泄漏的理想工具。
?