獲取顯存值
??安卓上debug顯存,除了游戲引擎自帶的profiler外,還有更底層的統(tǒng)計方式,用adb獲取內(nèi)存大小,命令為:
adb shell dumpsys meminfo <應(yīng)用包名>
??這可以獲取到類似下列的列表:
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
??和圖形相關(guān)的有如下信息:
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芯片的手機(jī)上獲取到的信息,而如果是在mali gpu的手機(jī)獲取,只會獲取到如下信息:
GL mtrack 111392 111392 0 0 111392\
Graphics: 111392 111392
??觀察上述信息,我們能簡單得到一些結(jié)論: adreno芯片獲取的信息中,Gfx dev + EGL mtrack + GL mtrack的結(jié)果,恰好是Graphics中的值。
??多次在手機(jī)運(yùn)行demo程序中,我發(fā)現(xiàn)多次用adb獲取上述信息時,adreno手機(jī)上,Gfx dev時刻在小范圍波動,每次獲取都不同;EGL mtrack不會輕易發(fā)生變化,GL mtrack和紋理相關(guān),在demo程序中添加紋理,大小會反應(yīng)在GL mtrack中,且紋理的大小幾乎就是GL mtrack的增量(有極小的差異,可能和其他渲染用資源有關(guān))。
??復(fù)制一個特效,再將其刪除,理論上只有shader不會被卸載,其他資源都應(yīng)該被卸載,反應(yīng)在上述結(jié)果中,GL mtrack再復(fù)制前和刪除后幾乎沒有變化,而Gfx dev有很大變化,說明Gfx dev內(nèi)包含Shader Program的內(nèi)存。
??mali芯片只有GL mtrack并和Graphics值相等,懷疑mali芯片獲取的GL mtrack中,包含了Gfx dev + EGL mtrack,不過與時刻變化的adreno芯片Gfx dev不同,mali芯片GL mtrack不會時刻變化,而是當(dāng)demo重新啟動時,每次重啟app,這里值都有微小差異。
發(fā)現(xiàn)的問題與調(diào)查問題
??在mali芯片的gpu中,我們播放的一個粒子特效后,內(nèi)存值顯著高于adreno芯片。
??在Android Studio的Profiler界面(View->Tool Windows->Profiler)可以查看內(nèi)存,其中包含Other、Code、Stack、Graphics、Native、Java等項:

對比上文中的adb命令其中的數(shù)值,可以判定這些值是用同一個方法拿到的(KB轉(zhuǎn)MB需要除以1024):


。

??將檢查部分改成Arrange by callstack展開內(nèi)容,用remaining size排序,首先是看起來是有0.5MB的紋理創(chuàng)建導(dǎo)致的內(nèi)存未清理,后面還有g(shù)lBindFramebuffer等申請的內(nèi)存未釋放,這些內(nèi)存是在libGLES.mali.so,也就是芯片廠商提供的動態(tài)庫內(nèi)部申請的。
??合理懷疑可不可能是Unity有些申請的紋理為釋放,因此用高通設(shè)備走同樣的流程對比,發(fā)現(xiàn)高通的remaining size也就不到400KB,并且也沒有紋理相關(guān)的堆棧,說明這與Unity無關(guān),是芯片廠dll內(nèi)部申請的內(nèi)存未釋放。
??將同一特效反復(fù)加載播放然后刪除,mali和adreno設(shè)備的曲線有明顯區(qū)別:

??因此幾乎可以判定,mali芯片的gles動態(tài)庫底層有一個池子。
堆棧內(nèi)存問題
??偶然中發(fā)現(xiàn),在mali設(shè)備上,Graphics峰值增長100MB時,堆棧才顯示分配了不到20MB,而高通設(shè)備上,分配大小顯著高于Graphics峰值,懷疑mali設(shè)備的統(tǒng)計上,至少有一個有問題。
??所以我將11張ASTC4x4紋理(10個2048每個5.3MB,1個1024 1.3MB,合計54.3MB)打為一個Bundle,在運(yùn)行時加載bundle并顯示渲染包含這些紋理的Cube,查看堆棧的增長情況:

??發(fā)現(xiàn)mali設(shè)備的堆棧申請大小才不到20MB,而高通上接近80MB,可以斷定,mali設(shè)備查這里的堆棧是有問題的。
??同時分別查看加載和卸載這50MB紋理的情況,在高通設(shè)備上,加載和卸載紋理時,Graphics幾乎沒有變化,而在adreno設(shè)備上,Graphics比加載紋理前多25MB。
其他情況
??同樣的示例打了Vulkan包試了試,Graphics釋放不全的問題,在mali vk上同樣適用,且對vulkan api的調(diào)度,會調(diào)度到libvulkan.so,然后再調(diào)用到底層的libGLES_mali.so,懷疑mali上vk是封裝了層gl?
??在adreno上測試,實際api調(diào)用是vulkan.adreno.so;結(jié)果50多MB的紋理創(chuàng)建,Graphics才增長32MB,且卸載Bundle銷毀紋理時,Graphics沒有一點(diǎn)下降,不是統(tǒng)計有問題,就是底層有什么機(jī)制。