一. 基本操作
1.1 抓取和打开trace文件
可通过ADM或控制台脚本来抓取trace,利用ADM抓取trace文件的操作如下:
- 在AndroidStudio中点击:Tools -> Android -> Android Device Monitor,打开ADM
- 在ADM中先选择已连接的设备,然后点击捕获按钮
- 设置参数 设置完参数后点击确定,即进入抓取状态,此时在手机上进行要测试的操作。时间到后,在会目标文件夹生成格式为html的文件。
- 打开chrome,在地址栏输入:chrome://tracing/,在出来的页面点击“load”,然后选择刚才生成的trace文件,此时文件会在chrome中打开
1.2 基本操作
操作(键盘按键) | 作用 |
---|---|
w | 放大当前视图 |
s | 缩小当前视图 |
a | 向左移动 |
d | 向右移动 |
f | 选中某一帧之后,放大当前区域 |
m | 选中某一帧之后,标记该帧 |
v | 高亮VSync线 |
g | 是否显示60hz标记线 |
0 | 数字0,恢复当前视图到初始状态 |
h | 是否显示详情 |
/ | 搜索关键字(title) |
enter | 显示搜索结果 |
` | 显示、隐藏脚本控制台 |
? | 显示帮助 |
1 | 切换到选择模式,双击已选定区能将所有相同的块高亮选中 |
2 | 切换到拖动模式,按下左键可拖动视图 |
3 | 切换到缩放模式,按下左键移动鼠标可缩放视图 |
4 | 切换到时间轴模式,可标记时间轴 |
1.3.分析trace文件
整体情况:
- 蓝色:整体较为流畅
- 黄色:中度掉帧
- 红色:有严重掉帧
每一帧的情况:
- 蓝色:没有掉帧
- 黄色:中度掉帧
- 红色:有严重掉帧
掉帧原因统计:
点击页面最右侧的“Alerts”:
从该图中,可看出本次测试的整体掉帧原因统计,点击可现实详情。
具体掉帧原因:
点击目标线程,选择一帧(点击每一帧的圆形图标,内有字符“F”),在界面下方会现实具体的掉帧原因,点击可展开:
从截图中可知,当前帧出现掉帧的原因有4个。
二. Systrace中的Title
下表为framework中常见的Trace title:
- Trace Title:Trace.traceBegin的第二个参数,用于表示当前监测的方法名,这个字符串不一定等于监测的函数名。
java Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceStop");
- 方法名:Trace真正监测的函数名
- 类名:方法所在的类 *Trace Category:Trace.traceBegin的第一个参数,用于表示监测的类别,Systrace支持的类别如下:
Systrace中,常见的Ttitle如下(红色加粗的title比较常见):
|序号|Trace Title|方法名|类名|Trace Category|
|:–:|:–|:–|:–|:–|
|1|activityStart
|handleLaunchActivity|ActivityThread|ActivityManager||
|2|activityRestart
|handleRelaunchActivity|ActivityThread|ActivityManager||
|3|activityPause
|handlePauseActivity|ActivityThread|ActivityManager||
|4|activityPause
|handlePauseActivity|ActivityThread|ActivityManager|pause后就finish|
|5|activityStop
|handleStopActivity|ActivityThread|ActivityManager|stop_show|
|6|activityStop
|handleStopActivity|ActivityThread|ActivityManager|stop_hide|
|7|activityShowWindow
|handleWindowVisibility|ActivityThread|ActivityManager|show|
|8|activityHideWindow
|handleWindowVisibility|ActivityThread|ActivityManager|hide|
|9|activityResume
|handleResumeActivity|ActivityThread|ActivityManager||
|10|activityDeliverResult
|handleSendResult|ActivityThread|ActivityManager||
|11|activityDestroy
|handleDestroyActivity|ActivityThread|ActivityManager||
|12|bindApplication
|handleBindApplication|ActivityThread|ActivityManager||
|13|activityNewIntent
|handleNewIntent|ActivityThread|ActivityManager||
|14|broadReceiverComp
|handleReceiver|ActivityThread|ActivityManager||
|15|serviceCreate
|handleCreateService|ActivityThread|ActivityManager||
|16|serviceBind
|handleBindService|ActivityThread|ActivityManager||
|17|serviceUnbind
|handleUnbindService|ActivityThread|ActivityManager||
|18|serviceStart
|handleServiceArgs|ActivityThread|ActivityManager||
|19|serviceStop
|handleStopService|ActivityThread|ActivityManager||
|20|configChanged
|handleConfigurationChanged|ActivityThread|ActivityManager||
|21|lowMemory
|handleLowMemory|ActivityThread|ActivityManager||
|22|activityConfigChanged
|handleActivityConfigurationChanged|ActivityThread|ActivityManager||
|23|backupCreateAgent
|handleCreateBackupAgent|ActivityThread|ActivityManager||
|24|backupDestroyAgent
|handleDestroyBackupAgent|ActivityThread|ActivityManager||
|25|providerRemove
|completeRemoveProvider|ActivityThread|ActivityManager||
|26|broadcastPackage
|handleDispatchPackageBroadcast|ActivityThread|ActivityManager||
|27|sleeping
|handleSleeping|ActivityThread|ActivityManager||
|28|setCoreSettings
|handleSetCoreSettings|ActivityThread|ActivityManager||
|29|trimMemory
|handleTrimMemory|ActivityThread|ActivityManager||
|30|activityThreadMain
|main|ActivityThread|ActivityManager|ActivityThread的main方法|
|31|参数,不定
|new PathClassLoader|ApplicationLoaders|ActivityManager||
|32|参数,不定
|new PathClassLoader|ApplicationLoaders|ActivityManager||
|33|broadcastReceiveReg
|onReceive|LoadedAok|ActivityManager|BroadcastReceiver的onReceive|
|34|参数,不定
|onPerformSync|AbstractThreaded|SyncManager||
|35|参数,资源文件名
|loadDrawableForCookie|Resources|Resources|加载Drawable|
|36|参数,资源文件名
|loadColorStateListForCookie|Resources|Resources|加载颜色|
|37|Choreographer#doFrame
|doFrame|Choreographer|View||
|38|参数,不定
|doCallbacks|Choreographer|View||
|39|inflate
|inflate|LayoutInflater|View||
|40|参数,view名称
|createView|LayoutInflater|View||
|41|Record View#draw()
|updateRootDisplayList|ThreadedRenderer|View||
|42|buildDrawingCache/SW Layer for+类名
|buildDrawingCache|View|View||
|43|measure
|performMeasure|ViewRootImpl|View|调用View的measure方法|
|44|layout
|performLayout|ViewRootImpl|View|调用View的layout方法|
|45|draw
|performDraw|ViewRootImpl|View|调用View的draw方法|
|46|getProvider()
|getProvider|WebViewFactory|WebView||
|47|newInstance()
|getProvider|WebViewFactory|WebView||
|48|loadNativeLibrary()
|loadNativeLibrary|WebViewFactory|WebView||
getChromiumProvider()
|49||getChromiumProviderClass|WebViewFactory|WebView||
Class.forName(
|50|)|getChromiumProviderClass|WebViewFactory|WebView||
obtainView
|52|****|obtainView|AbsListView|View||
setupGridItem
|52|****|setupChild|GridView|View||
setupListItem
|53|****|setupChild|ListView|View||
RuntimeInit
|54||zygoteInit|RuntimeInit|ActivityManager||
PostFork
|55||forkAndSpecialize|Zygote|ActivityManager||
Bitmap.compress
|56||compress|Bitmap|Resources||
decodeBitmap
|57|****|decodeByteArray|BitmapFactory|Graphics||
decodeBitmap
|58||decodeStream|BitmapFactory|Graphics||
decodeFileDescriptor
|59||decodeFileDescriptor|BitmapFactory|Graphics||
参数,文件名
|60||createFromStream|Drawable|Resources||
参数,文件名
|61||createFromResourceStream|Drawable|Resources||
参数,路径名
|62||createFromPath|Drawable|Resources||
onSurfaceCreated
|63||onSurfaceCreated|GLSurfaceView|View||
onSurfaceChanged
|64||onSurfaceChanged|GLSurfaceView|View||
onDrawFrame
|65||onDrawFrame|GLSurfaceView|View||
syncAll
|66||syncAll|Allocation|RenderScript||
ioSend
|67||ioSend|Allocation|RenderScript||
ioReceive
|68||ioReceive|Allocation|RenderScript||
copyFrom
|69||copyFrom|Allocation|RenderScript||
copyFromUnchecked
|70||copyFromUnchecked|Allocation|RenderScript||
copyFromUnchecked
|71||copyFromUnchecked|Allocation|RenderScript||
copyFrom
|72||copyFrom|Allocation|RenderScript||
copyFrom
|73||copyFrom|Allocation|RenderScript||
copyFrom
|74||copyFrom|Allocation|RenderScript||
copy1DRangeFromUnchecked
|75||copy1DRangeFromUnchecked|Allocation|RenderScript||
copy1DRangeFrom
|76||copy1DRangeFrom|Allocation|RenderScript||
copy2DRangeFromUnchecked
|77||copy2DRangeFromUnchecked|Allocation|RenderScript||
copy2DRangeFrom
|78||copy2DRangeFrom|Allocation|RenderScript||
copy2DRangeFrom
|79||copy2DRangeFrom|Allocation|RenderScript||
copy2DRangeFrom
|80||copy2DRangeFrom|Allocation|RenderScript||
copy3DRangeFromUnchecked
|81||copy3DRangeFromUnchecked|Allocation|RenderScript||
copy2DRangeFrom
|82||copy2DRangeFrom|Allocation|RenderScript||
copyTo
|83||copyTo|Allocation|RenderScript||
copyTo
|84||copyTo|Allocation|RenderScript||
copy1DRangeToUnchecked
|85||copy1DRangeToUnchecked|Allocation|RenderScript||
copy2DRangeToUnchecked
|86||copy2DRangeToUnchecked|Allocation|RenderScript||
copy3DRangeToUnchecked
|87||copy3DRangeToUnchecked|Allocation|RenderScript||
createTyped
|88||createTyped|Allocation|RenderScript||
createSized
|89||createSized|Allocation|RenderScript||
createFromBitmap
|90||createFromBitmap|Allocation|RenderScript||
killProcessGroup
|91||killProcessGroup|AMS|ActivityManager||
Start proc:+进程名
|92||Process.start|AMS|ActivityManager||
kill
|93||kill|ProcessRecord|ActivityManager||
requestGlobalDisplay
|94||requestGlobalDisplay|DisplayManagerService|Power||
setDisplayState
|95||requestDisplayStateLocked|LocalDisplayAdapter|Power||
setDisplayBrightness
|96||requestDisplayStateLocked|LocalDisplayAdapter|Power||
startDream
|97||startDream|DreamController|Power||
stopDream
|98||stopDream|DreamController|Power||
setLight
|99||setLightLocked|LightsService|Power||
userActivity
|100||userActivityNoUpdateLocked|PowerManagerService|Power||
wakeUp
|101||wakeUpNoUpdateLocked|PowerManagerService|Power||
goToSleep
|102||goToSleepNoUpdateLocked|PowerManagerService|Power||
nap
|103||napNoUpdateLocked|PowerManagerService|Power||
reallyGoToSleep
|104||reallyGoToSleep|PowerManagerService|Power||
updatePowerState
|105||updatePowerStateLocked|PowerManagerService|Power||
setHalAutoSuspend
|106||setHalAutoSuspend|PowerManagerService|Power||
setHalInteractive
|107||setHalInteractiveModeLocked|PowerManagerService|Power||
wmLayout
|108||performLayoutAndPlace|WMS|WindowManager||
wmUpdateFocus
|109||updateFocusedWindowLocked|WMS|WindowManager||
calculateError
|110||calcErrorRS|AutomaticActivity|Always||
loadBitmaps
|111||loadBitmaps|CompareActivity|Always||
softwareDraw
|112||loadBitmaps|CompareActivity|Always||
copyInto
|113||loadBitmaps|CompareActivity|Always||
pretendBusy`|performClick|CirclePropActivity|View|Thread.sleep|
|114|
注意:由于显示问题,上表中部分内容有所精简,具体如下:
- 34行,类名为:AbstractThreadedSyncAdapter
- 46行,title为:webViewFactory.getProvider()
- 47行,title为:providerClass.newInstance()
- 49行,title为:getChromiumProviderClass()
- 94行,title为:requestGlobalDisplayState
- 94行,方法为:requestGlobalDisplayStateInternal
- 104行,方法为:reallyGoToSleepNoUpdateLocked
- 106行,方法为:setHalAutoSuspendModeLocked
- 48行,title为:WebViewFactory.loadNativeLibrary()
- 49行,title为:WebViewFactory.getChromiumProviderClass()
- 108行,方法为:performLayoutAndPlaceSurfacesLockedLoop
三. 常见卡顿原因
3.1 Scheduling delay
产生这一帧的任务延时了若干毫秒,导致出现了掉帧。要保证UI线程在工作时不会被其他线程阻塞,后台线程(比如网络请求、Bitmap加载等)应该运行在android.os.Process.THREAD_PRIORITY_BACKGROUD或更低的优先级,以确保它们不会中断UI线程。
3.2 Inefficient ListView recycling / rebinding
ListView的回收在一帧中占用了太多的时间,确保在Adapter的getView方法中高效的绑定数据。
3.3 Expensive measure/layout pass
Measure/Layout占用了大量的时间导致掉帧,避免在执行动画时触发layout。
这种场景非常常见:在首次进入一个有ListView的页面时经常出现这种情况,ListView在首次加载时,RecycleBin中并没有可以复用的数据,此时,每一个要显示的Item对于的View都需要从布局文件中inflate出来,而inflate又是比较耗时的,因此,当同时需要加载多个View时,就会导致较严重的掉帧。
3.4 Inflating duraing ListView recycling
ListView会回收已经加载过的View,确保在getView时复用已存在的view,而不是创新创建一个新的。
3.5 Long View.draw
在View的绘制过程中要避免执行大量的耗时工作,尤其是分配和对象和绘制Bitmap
3.6 Expensive Bitmap uploads
被修改的Bitmap和新绘制的Bitmap都必需要上传到GPU中。如果上传的像素太多,这将是一个非常昂贵的操作,要尽量减少Bitmap的改动。
3.7 gc导致线程暂停
这种场景比较少见,而且GC导致的pause时间也较短,一般在10ms以内,很少会因为gc导致掉帧,如下面的两个截图所示:
如下图所示,full suspand check
Checkpoint function