Android调试工具介绍
meminfo参数 :Java中关于内存泄漏出现的原因以及如何避免内存泄漏(超详细版汇总下)_移动开发Android-CSDN博客
adb shell dumpsys meminfo pkgname|pid -d
Private(Clean and Dirty) RAM, 进程使用的内存,进程销毁后系统可回收的RAM容量,
PSS proportional set size, 实际使用的物理内存,比例分享共享库占用的内存,考虑了进程之间共享RAM的情况,
DalvikHeap,应用中dalvik分配所占用的RAM,Pss total包括所有zygote分配,private dirty是仅分配给你应用堆得实际RAM,包含了您自己的分配和任何zygote分配页。
Heap alloc,是dalvik和原生堆分配器为你的应用记录的内存占用量,此值大于pss total, private dirty,因为你的进程是从zygote孵化而来,所以他包含了你的进程和其他的进程的共享分配。
.so mmap, .dex mmap,这块内存用于映射 .so(native)和.dex(dalvik/art)代码占用的RAM,Pss total 值包括应用之间共享的平台代码,Private clean是你应用自己的代码,
通常实际映射的内存容量要大得多,此处的RAM只是应用已经执行的代码当前需要占用的RAM。
.oat mmap,这个等同于代码镜像占用的RAM,它是基于被多个应用预加载的类来计算的,这个镜像在所有应用之间共享,不受特定应用影响。
.art mmap, 这个等同于堆镜像占用的RAM,它是基于被多个应用预加载的类来计算,此镜像在所有应用之间共享,不受特定应用影响,即使ART镜像包含Object实例,也不会计入你的堆空间。
Unkown, 系统无法将其分类到其他更具体的一项RAM页,当前,此类RAM页主要包含native分配,工具在收集此数据时无法识别这些分配。
ViewRootImpl,当前进程中,处于活动状态的跟实图数量,每个根视图都与一个窗口关联。
AppContexts, Activities, 当前进程中,当前处于活跃状态的应用上下文,和activity对象数量
微信团队手把手教你监控卡顿!-技术圈 (proginn.com)
微信团队手把手教你监控卡顿!-技术圈 (proginn.com)https://jishuin.proginn.com/p/763bfbd6a471
查看帧率:
adb shell
setprop debug.sf.showfps 1
logcat | grep fps
输出log:
01-10 11:24:15.554 399 582 D SDM : HWCDisplay::DebugShowFps: fps=4
在帧率偏低情况下,查看cpu,gpu利用率:
adb shell
su
cd sys/class/debfreq
ls
msm8909go_benz:/sys/class/devfreq # ls
1c00000.qcom,kgsl-3d0 mmc0 soc:qcom,cpubw soc:qcom,gpubw soc:qcom,kgsl-busmon
cd lc00000.qcom,kgsl-3d0
msm8909go_benz:/sys/class/devfreq/1c00000.qcom,kgsl-3d0 # ls
available_frequencies available_governors cur_freq device governor gpu_load max_freq min_freq polling_interval power subsystem suspend_time target_freq trans_stat uevent
cat cur_freq
msm8909go_benz:/sys/class/devfreq/1c00000.qcom,kgsl-3d0 # cat cur_freq
307200000
msm8909go_benz:/sys/class/devfreq/1c00000.qcom,kgsl-3d0/device/kgsl/kgsl-3d0 # cat gpu_busy_percentage
6 %
dump Framebuffer的每一帧:
1) service call SurfaceFlinger 1008 i32 1 (开机设置一次就可以了)
2) setprop debug.sf.dumptofile 3 (dump framebuffer,每一帧)
3) setprop debug.sf.dumptofile 0 (stop dump,及时关闭,否则dump会很多)
simpleperf
C:\Users\jianlin\AppData\Local\Android\Sdk\ndk\22.1.7171670\simpleperf\perfdata>
Android\Sdk\ndk\22.1.7171670\toolchains\aarch64-linux-android-4.9\prebuilt\windows-x86_64\bin>aarch64-linux-android-objdump.exe -TC libTest.so >text.txt
adb shell /data/local/tmp/perfd/simpleperf_arm64 record -o /data/local/tmp/perf.data -g --app com.*** --duration 5 -f 1000
adb shell /data/local/tmp/perfd/simpleperf record -o /data/local/tmp/perf.data -g --app com.*** --duration 5 -f 1000
adb shell pkill -l 2 simpleperf
adb pull data/local/tmp/perf.data .
生成普通数据报告
python .\report.py -i .\perfdata\perf.data -o .\perfdata\report.txt -n --full-callgraph --symfs app\build\intermediates\cmake\debug\obj\arm64-v8a
生成调用者耗时分布数据报告
python .\report.py -i .\perfdata\perf.data -o .\perfdata\report.caller.txt -g caller --full-callgraph --symfs app\build\intermediates\cmake\debug\obj\arm64-v8a
生成被调用者耗时分布数据报告
python .\report.py -i .\perfdata\perf.data -o .\perfdata\report.callee.txt -g callee --full-callgraph --symfs app\build\intermediates\cmake\debug\obj\arm64-v8a
用simpleperf提供的report_html.py生成可视图
python .\report_html.py -i .\perfdata\perf.data -o .\perfdata\report.html --binary_filter app\build\intermediates\cmake\debug\obj\arm64-v8a
一、DDMS
1, Logcat:
在log窗口中,每条信息包含:
(1)Level –表示信息的类别,分为V,D,I,W,E五种,根Log.java中函数对应:
V:verbose,显示全部信息;D:Debug,显示调试信息;I:Info,显示一般信息;W:Warming,显示警告信息;E:Error,显示错误信息。
(2)Time:表示执行的时间。
(3)PID:表示程序运行时的进程号。
(4)TID:表示线程号。
(5)application:应用程序名。
(6)tag:标签。
(7)text:表示一些具体信息。
2,Dump Heap信息(下图红色线标记的按钮):
内存检测工具,检测一个进程的内存变化。
具体操作步骤:
(1) 选中要检测的进程后,Heap按钮会由灰色变为可用。
(2) 点击updateHeap,打开heap视图,然后点击CauseGC。
(3) 操作应用,会看到HeapSize,Data Object值的变化。
(4) 点击DumpHprof file文件,自动保存后缀是.hprof的文件。
保存的.hprof要用hprof-conv.exe转一下才能用mat工具打开;
在Eclipse中通过ADT保存的.hprof可以直接打开。
hprof-conv.exe的用法:
hprof-conv.exe –zres.hprof dest.hprof
代码中添加log,保存dumphprof数据:
android.os.Debug.dumpHprofData(path);
通常定位内存问题流程:先是使用Memory Monitor观察程序是否经常性的发生gc事件,发生gc就会有相应的gc日志;如果有经常gc,利用Heap Viewer来帅选可疑对象,这时可能用到mat工具;最后借助Allocation Tracker确定发生问题的代码位置,Allocation tracker可以获取各个对象的分配情况,包括时间顺序、线程号、对象创建时的调用堆栈等。
3, TraceView数据的采集-method profiling
如下图的红色划线的按钮。
使用方法:
(1)选中要采集数据的进程,点击updatethreads按钮
(2)点击stopmethod profiling按钮,会保存一个.trace的文件,DDMS自动触发traceview工具浏览采集到的数据。
也可以在代码中通过函数来实现,在一段关键代码前调用:Debug.startMethodTracing("traceTest");
在关键代码后调用:Debug.stopMethodTracing();
这两个函数运行过程中将采集这段时间内该应用所有线程的函数执行情况,并把数据保存到一个后缀.trace的文件中。
文件存储的路径:data/media/0/Android/com.android.gallery3d/files/
4, 收集Android关键子系统的运行信息 –systemtrace
参考:Systrace 流畅性实战 1 :了解卡顿原理 · Android Performance
Systrace 流畅性实战 1 :了解卡顿原理 · Android Performance
如下图红色圆圈标记的按钮。
对应代码中的函数调用:
Trace.java中函数,如:
public static void traceBegin(long traceTag, String methodName);
public static void traceEnd(long traceTag);
二,内存分析工具:MAT –MemoryAnalyzer
1,打开MAT,选择转化好的hprof文件,可以看到如下视图:
2,其中有一项:Leak Suspects泄漏怀疑点,这个是根据对象占的比例列出的可能的泄漏点,不一定是实际的泄漏点。
另一个对比的hprof文件中histogram也以同样的方式添加compare,如下图:
* public void onCreate() {
* if (DEVELOPER_MODE) {
* StrictMode.setThreadPolicy(new {@link ThreadPolicy.Builder StrictMode.ThreadPolicy.Builder}()
* .detectDiskReads()
* .detectDiskWrites()
* .detectNetwork() // or .detectAll() for all detectable problems
* .penaltyLog()
* .build());
* StrictMode.setVmPolicy(new {@link VmPolicy.Builder StrictMode.VmPolicy.Builder}()
* .detectLeakedSqlLiteObjects()
* .detectLeakedClosableObjects()
* .penaltyLog()
* .penaltyDeath()
* .build());
* }
* super.onCreate();
* }
2, Histogram,统计了每个对象的个数;
Dominator Tree,列举了程序中最占内存的对象。
这2个视图中都可以支持正则表达式搜索具体的类名字。
下图是直方图的界面:
搜索具体对象的视图:
右键点击一行à选择:Merge Shortest paths To GC Rootsà选择exclude weak/soft.references
展开查看是不是有对象被GCroot关联到。
支配树的分析跟这个是类似的。
3,数据对比,以直方图为例,在底部的OverViewPane下,右键选择:Add to Compare Basket ,
然后点击CompareBasket面板右上角“!”按钮,得到比较结果,如下图:
通过上面红圈的菜单,可以选择不同的比较选项。
三,systrace性能数据采集和分析工具
收集Android子系统的运行信息。
\sdk\platform-tools\systrace\systrace.py
通常用命令行形式来生成数据文件,如下图执行红色划线部分命令,抓取结束后会生成trace.html文件:
其中,最后面的一些参数指定要收取那些系统的运行信息:
gfx – Graphics
input – Input
view – View
webview –WebView
wm – WindowManager
am – ActivityManager
audio – Audio
video – Video
camera –Camera
hal – HardwareModules
res – ResourceLoading
dalvik –Dalvik VM
rs –RenderScript
sched – CPUScheduling
freq – CPUFrequency
membus –Memory Bus Utilization
idle – CPUIdle
disk – Diskinput and output
load – CPULoad
sync– Synchronization Manager
生成的trace.html文件,用chrome浏览器打开,
左边区域有cpu信息,Alters,Frames信息,一些用户进程的跟踪等;
右边区域是每一个帧的信息;
当选择一帧后按M键可以高亮这帧,左下角会有这一帧的详细信息。
选中Alters的视图
如下图是一个方法执行时间过长的警告:
这里可以看到问题的描述,
还有调度延迟的警告:
选中Frames的视图,分别用红,黄,绿来区分每一帧绘制时的性能
如下图是选择(红色)一帧的信息:
可以看到它的绘制时长,跟这帧相关的警告,存在的调度问题,方法执行时间过长问题,
展开详细信息:
可以看到这帧的绘制耗时是85ms,大大超过保证平滑的16ms。
下图是一个调度延迟导致渲染过慢的问题
调度延迟就是这个线程很长一段时间内没有分配到cpu来做运算,比如选这一帧中时间最长那块,来得到更详细的信息。
下图是这一帧中较长那块的详细信息:
其中Wall Duration:是这一块从开始到结束的时间;
CpuDuration:是实际cpu在处理这一块消耗的时间。
这2块时间差距很大,就去看下这个过程中cpu干嘛去了。
如下图是当前cpu的信息:
这里可以看到当前cpu被那个应用那个线程占用了,Systrace是一个概览,要找到具体是什么原因让cpu很忙,就要借助traceview了。
线程状态查看:
绿色 : 运行中
只有在该状态的进程才可能在CPU上运行。而同一时刻可能有多个进程处于可执行状态,这些进程的task_struct结构(进程控制块)被放入对应CPU的可执行队列中(一个进程最多只能出现在一个CPU的可执行队列中)。进程调度器的任务就是从各个CPU的可执行队列中分别选择一个进程在该CPU上运行。
作用:我们经常会查看 Running 状态的线程,查看其运行的时间,与竞品做对比,分析快或者慢的原因:
- 是否频率不够?
- 是否跑在了小核上?
- 是否频繁在 Running 和 Runnable 之间切换?为什么?
- 是否频繁在 Running 和 Sleep 之间切换?为什么?
- 是否跑在了不该跑的核上面?比如不重要的线程占用了超大核
蓝色 : 可运行
线程可以运行但当前没有安排,在等待 cpu 调度
作用:Runnable 状态的线程状态持续时间越长,则表示 cpu 的调度越忙,没有及时处理到这个任务:
- 是否后台有太多的任务在跑?
- 没有及时处理是因为频率太低?
- 没有及时处理是因为被限制到某个 cpuset 里面,但是 cpu 很满?
- 此时 Running 的任务是什么?为什么?
白色 : 休眠中
线程没有工作要做,可能是因为线程在互斥锁上被阻塞。
作用 : 这里一般是在等事件驱动
橘色 : 不可中断的睡眠态 IO Block
线程在I / O上被阻塞或等待磁盘操作完成,一般底线都会标识出此时的 callsite :wait_on_page_locked_killable
作用:这个一般是标示 IO 操作慢,如果有大量的橘色不可中断的睡眠态出现,那么一般是由于进入了低内存状态,申请内存的时候触发 pageFault, linux 系统的 page cache 链表中有时会出现一些还没准备好的 page(即还没把磁盘中的内容完全地读出来) , 而正好此时用户在访问这个 page 时就会出现 wait_on_page_locked_killable 阻塞了. 只有系统当 io 操作很繁忙时, 每笔的 io 操作都需要等待排队时, 极其容易出现且阻塞的时间往往会比较长.
紫色 : 不可中断的睡眠态
线程在另一个内核操作(通常是内存管理)上被阻塞。
作用:一般是陷入了内核态,有些情况下是正常的,有些情况下是不正常的,需要按照具体的情况去分析
四,traceview.bat
现在不推荐使用这个工具打开traceTest.trace文件,而是使用monitor.bat来代替。
如下是用monitor打开trace的一个截图:
图的上半部分是当前进程中每个线程的执行情况。下半部分是每个方法执行的详细信息。
如下是点击一个方法展开的截图:
其中,Parents是调用这个方法的方法,或者叫父方法;
Children是这个方法中会调用的其他方法,或者叫子方法。
这些方法会包括jdk的,sdk的,native的等等。
如下图是方法运行的详细信息:
其中:Incl Cpu Time是这个方法及子方法占用的总的cpu时间;
Excl Cpu Time是父方法的Incl Cpu Time时间减去每个子方法的Incl Cpu Time时间后的剩余值;
Incl Realtime是方法实际的执行时间;
Calls+RecurCalls/Total某个方法被调用次数+递归调用次数占总调用次数的比例;
Realtime/Call某个方法平均的执行时间;
Cpu time/Call某个方法平均占用的cpu时间。
五,lint.bat代码扫描工具
优化:布局性能,未使用的资源,数组大小问题,manifest错误等。
Android Studio中,通过菜单:AnalyzeàInspect CodeàSpecify Inspection Scope
确定后会执行lint命令。
命令使用方式:
如下图:生成报告截图
如下图:展开上图中红色圈中的异常的详细信息:
六,draw9patch.bat:处理.9格式图片的拉伸。
七,hierarchyviewer.bat查看UI布局结构。
八,tombstone分析静态库中的异常
\prebuilts\tools\gcc-sdk\addr2line
Add2line解析静态库中的行号。
要使用没有去除symbols符号的库,对应的是:
\out\target\product\msm8909\symbols\system\lib这个目录下的库文件,使用方法是:
Tombstone_00文件信息:
addr2line -f -elibart.so 0000000000220fc8
-f是把函数名也打出来,
-e接对应的库,
0000000000220fc8地址信息,
九,StrictMode 开发工具,检测代码中是否有违规操作
主要用于捕获在应用主线程中执行的偶然的磁盘读写,网络访问,当收到UI操作和动画执行时,应该让磁盘读写、网络操作远离主线程。
基本用法:
setThreadPolicy 表示策略应用在指定的线程,
detectDiskReads ,detectDiskWrites 检测磁盘读写,
detectNetwork 检测网络访问。
detectCustomSlowCalls 检测某些方法是否执行缓慢,
detectResourceMismatches 检测资源匹配,
penaltyDialog(),检测到违规行为后,显示一个对话框,
penaltyDeath(), crash掉有违规行为的进程,这个操作是在所有penalties的最后执行,在进程dies之前,依然可以看到log,或者其他的违规行为,
penaltyLog(),检测到违规后,输出系统log,
setVmPolicy ,应用于进程中的所有线程,
setClassInstanceLimit(),设置类实例的上限,
detectActivityLeaks(),检测Activity的内存泄漏,
detectLeakedSqlLiteObjects(),检测数据库实例是否有泄漏,如sqlitecursor或者sqlite object已经finalized了,但是没有closed,
detectLeakedRegistrationObjects(),检测broadcastreceiver,serviceconnection,注册与反注册是否配对使用了。
penaltyDropBox(),违规信息,存入到dropbox中。
十,DropBox,这个服务可以记录Android长时间运行过程中的异常信息
记录系统运行过程中kernel,app,系统进程出现的问题,如crash,anr,what terriable failure,strictmode,lowmem,netstats error,system restart等异常的捕获。
然后在data/system/dropbox下生成相应的.txt异常log,log会显示什么类型的问题,那个进程出现的,及相关的堆栈信息。
附:
1,adb shell dumpsys gfxinfo com.***
2,systrace命令行
python版本27.
在C:\Users\ii\AppData\Local\Android\Sdk\platform-tools\systrace 目录下执行命令:
python systrace.py -b 16384 -t 8 gfx input view webview sm hal idle freq sched wm am res dalvik disk sync -o mytrace.html
---------------
gfx - Graphics
input - Input
view - View System
webview - WebView
wm - Window Manager
am - Activity Manager
sm - Sync Manager
audio - Audio
video - Video
camera - Camera
hal - Hardware Modules
res - Resource Loading
dalvik - Dalvik VM
rs - RenderScript
bionic - Bionic C Library
power - Power Management
pm - Package Manager
ss - System Server
database - Database
network - Network
adb - ADB
vibrator - Vibrator
aidl - AIDL calls
pdx - PDX services
sched - CPU Scheduling
irq - IRQ Events
i2c - I2C Events
freq - CPU Frequency
idle - CPU Idle
disk - Disk I/O
sync - Synchronization
workq - Kernel Workqueues
memreclaim - Kernel Memory Reclaim
regulators - Voltage and Current Regulators
binder_driver - Binder Kernel driver
binder_lock - Binder global lock trace
pagecache - Page cache
-------------
在app添加自己的systrace log
Trace.traceBegin("performTraversals");
try {
……
} finally {
Trace.traceEnd();
}
需要保证 traceBegin 与 traceEnd 一定要成对出现。 并且一定要在同一个线程里面
------------------
systrace.py 命令参数
-h, --help show this help message and exit
-o FILE write HTML to FILE
-t N, --time=N trace for N seconds
-b N, --buf-size=N use a trace buffer size of N KB
-k KFUNCS, --ktrace=KFUNCS
specify a comma-separated list of kernel functions to
trace
-l, --list-categories
list the available categories and exit
-a APP_NAME, --app=APP_NAME
enable application-level tracing for comma-separated
list of app cmdlines
--no-fix-threads don't fix missing or truncated thread names
--no-fix-tgids Do not run extra commands to restore missing thread to
thread group id mappings.
--no-fix-circular don't fix truncated circular traces
--no-compress Tell the device not to send the trace data in
compressed form.
--link-assets (deprecated)
--boot reboot the device with tracing during boot enabled.
The report is created by hitting Ctrl+C after the
device has booted up.
--from-file=FROM_FILE
read the trace from a file (compressed) rather than
running a live trace
--asset-dir=ASSET_DIR
(deprecated)
-e DEVICE_SERIAL, --serial=DEVICE_SERIAL
adb device serial number
--agent-dirs=AGENT_DIRS
the directories of additional systrace agent modules.
The directories should be comma separated, e.g.,
--agent-dirs=dir1,dir2,dir3. Directory |agents| is the
default agent directory and will always be checked.
--target=TARGET chose tracing target (android or linux)
十一,ANR问题: