解bug的时候多,写代码的时候少。(后面可以按照CodeSheep所说,在github找开源项目跟着写写)
解bug遇到的最多的算是:CPU kernel panic, GPU hang ,Memory leak
memory leak来源:
找这个问题不看虚拟地址,看的是物理地址,比如PSS,顺便带了平均分的共享库大小。
哪些命令可以看PSS?
- ps
- procrank
- dumpsys meminfo
这些命令可以连接串口看,或者连接adb看。
我习惯性的用procrank居多,除了看占用PSS最多的AP,在结尾还可以看到总RAM统计,其中cached也算是free ram的。
(为什么不适用dumpsys meminfo?他与procrank有什么区别?)
有时会跑stress,看RAM变化,来找哪个AP在leak,或者只是看眼前的1分钟内的变化,可以用一句shell:
while : ; do free ; procrank ; sleep 1 ; done ;
看总RAM里Free arm的变化,如果发现了确实有leak,需要分析leak来自哪里,一共有3个地方:
- java heap
- native heap
- gpu heap
如果看到了某个AP有leak,就可以通过dumpsys meminfo <pid> 看它的java heap与native heap,
native heap可以来自AP的cpp层,也可能是链接的动态库出了问题,而不是AP本身的代码有问题。我主要关注的就是OGLES_v2.so,这里的代码庞大臃肿,且注释稀少,一般没人敢动,只是打patch,基于混乱的理解,让他愈发臃肿。
native heap memleak:
OGLES_v2.so里会有很多malloc的地方,最大的malloc不在结构体,而在对临时buffer的system memory malloc,这种很容易看,因为它太大了,一个buffer可能有1M-8M。
如果是很小的leak,就是哪里的malloc没有free,
这里有一个方法来查看一个AP内native heap的使用情况:
- am dumpheap -n <pid> name.log
要使用这个命令,需要在build.prop设置一些东西,网上和android源码里面的help,都是在Android 5.0上生效的,但android 7.0有变化。当时看过android 7.0这部分源码,才看到怎么去配置:
//在/system/build.prop
libc.debug.malloc.program = app_process //这个不写也能dump出来
libc.debug.malloc.options = backtrace
然后运行命令am dumpheap,得到name.log,复制到有android源码的host机,原因是需要out/下带symbol的so库,以便于定位malloc最多的动态库中代码行数。
有一个解析name.log的python脚本,来自github,叫做native_heapdump_viewer.py。
先指定带symbol的动态库所在位置,然后解析log为html:
//注意这个路径一定是到/symbol/的,否则不生效
export ANDROID_PRODUCT_OUT=/<android>/out/target/product/zx2100_148a//symbols/
native_heapdump_viewer.py --symbols /some/path/to/symbols/ heap.log > heap_info.html
这样查看html就可以知道,一个AP的总native heap,和每个函数的malloc占比。从而定位问题。
GPU driver heap memleak:
java heap我们平时不会管,在我们看来这是AP问题,不负责处理。
如果看到java heap与native heap都没有变化,而Procrank里total free ram还在减少,那几乎可以定位是我们的GPU driver出现的leak。
GPU driver会先从RAM里面reserve一块作为自己内部的显存:local memory(video memroy),我也不知道为什么这么叫,microsoft也是这么叫的。
local memory一般大概有96M,在device tree配置,后面还有会从system memroy动态拿的部分,称为pcie memory。这部分会很大,按照不同的compress snoop配对,分4个segment。最大的segment会有512M,需要多少拿多少。所以这部分有机会leak。
(snoop是什么?)
检查方法是cat /proc/driver/gpu_driver_name,
这里我们的driver会打印所有的segment中的allocation,通过at_type,就可以看出是谁要求分配的allocation。比如是OGLES,或者是Gralloc。
什么是snoop:
在get_allocation_segment_id时,可以看到,
- 如果有compress_format,就分到COMPRESS,一个HwFormatTable负责hwFormat(HSF_XXX)到CompressFmt(CP_XXX)的映射,不支持就是CP_OFF。
- 若有USAGE_TEMP/DATA_BUFFER,就用snoopable。
GRALLOC_USAGE_HW_2D就会置USAGE_TEMP_BUFFER
网友评论