获取显存值
安卓上debug显存,除了游戏引擎自带的profiler外,还有更底层的统计方式,用adb获取内存大小,命令为:
xml
adb shell dumpsys meminfo <应用包名>
这可以获取到类似下列的列表:
yaml
Applications Memory Usage (in Kilobytes):
Uptime: 1307163772 Realtime: 1442234389
** MEMINFO in pid 26060 [games.guanyou.ca.ymr] **
Pss Private Private SwapPss Rss Heap Heap Heap
Total Dirty Clean Dirty Total Size Alloc Free
------ ------ ------ ------ ------ ------ ------ ------
Native Heap 30104 30024 12 105 30888 48356 45145 3212
Dalvik Heap 1815 1676 36 74 2616 11550 2887 8663
Dalvik Other 1668 1556 56 0 2172
Stack 1892 1892 0 0 1900
Ashmem 136 0 0 0 1020
Gfx dev 392 392 0 0 396
Other dev 19 4 8 0 544
.so mmap 77560 11596 61188 8 111328
.jar mmap 4411 0 2012 0 44044
.apk mmap 441 0 12 0 1812
.ttf mmap 2213 0 384 0 5584
.dex mmap 7177 52 7072 0 7936
.oat mmap 31 0 0 0 2004
.art mmap 7700 5656 1060 43 16472
Other mmap 10389 8 10220 0 11420
EGL mtrack 37000 37000 0 0 37000
GL mtrack 764 764 0 0 764
Unknown 16209 16068 92 1 16596
TOTAL 200152 106688 82152 231 294496 59906 48032 11875
App Summary
Pss(KB) Rss(KB)
------ ------
Java Heap: 8392 19088
Native Heap: 30024 30888
Code: 82316 172756
Stack: 1892 1900
Graphics: 38156 38160
Private Other: 28060
System: 11312
Unknown: 31704
TOTAL PSS: 200152 TOTAL RSS: 294496 TOTAL SWAP PSS: 231
和图形相关的有如下信息:
makefile
Gfx dev 392 392 0 0 396
EGL mtrack 37000 37000 0 0 37000
GL mtrack 764 764 0 0 764
Graphics: 38156 38160
上述是在adreno芯片的手机上获取到的信息,而如果是在mali gpu的手机获取,只会获取到如下信息:
makefile
GL mtrack 111392 111392 0 0 111392\
Graphics: 111392 111392
观察上述信息,我们能简单得到一些结论: adreno芯片获取的信息中,Gfx dev + EGL mtrack + GL mtrack的结果,恰好是Graphics中的值。
多次在手机运行demo程序中,我发现多次用adb获取上述信息时,adreno手机上,Gfx dev时刻在小范围波动,每次获取都不同;EGL mtrack不会轻易发生变化,GL mtrack和纹理相关,在demo程序中添加纹理,大小会反应在GL mtrack中,且纹理的大小几乎就是GL mtrack的增量(有极小的差异,可能和其他渲染用资源有关)。
复制一个特效,再将其删除,理论上只有shader不会被卸载,其他资源都应该被卸载,反应在上述结果中,GL mtrack再复制前和删除后几乎没有变化,而Gfx dev有很大变化,说明Gfx dev内包含Shader Program的内存。
mali芯片只有GL mtrack并和Graphics值相等,怀疑mali芯片获取的GL mtrack中,包含了Gfx dev + EGL mtrack,不过与时刻变化的adreno芯片Gfx dev不同,mali芯片GL mtrack不会时刻变化,而是当demo重新启动时,每次重启app,这里值都有微小差异。
发现的问题与调查问题
在mali芯片的gpu中,我们播放的一个粒子特效后,内存值显著高于adreno芯片。
在Android Studio的Profiler界面(View->Tool Windows->Profiler)可以查看内存,其中包含Other、Code、Stack、Graphics、Native、Java等项:
用左侧Record native allocation可以记录堆栈申请的内存,并根据开始与结束时内存的释放,查看是否有未释放的内存,例如我record灰色部分:
。
将检查部分改成Arrange by callstack展开内容,用remaining size排序,首先是看起来是有0.5MB的纹理创建导致的内存未清理,后面还有glBindFramebuffer等申请的内存未释放,这些内存是在libGLES.mali.so,也就是芯片厂商提供的动态库内部申请的。
合理怀疑可不可能是Unity有些申请的纹理为释放,因此用高通设备走同样的流程对比,发现高通的remaining size也就不到400KB,并且也没有纹理相关的堆栈,说明这与Unity无关,是芯片厂dll内部申请的内存未释放。
将同一特效反复加载播放然后删除,mali和adreno设备的曲线有明显区别:
因此几乎可以判定,mali芯片的gles动态库底层有一个池子。
👀关注公众号:Android老皮!!!欢迎大家来找我探讨交流👀