美文网首页
Android显存profile方法、mali芯片显存占用高的问

Android显存profile方法、mali芯片显存占用高的问

作者: crossous | 来源:发表于2024-07-11 09:57 被阅读0次

获取显存值

  安卓上debug显存,除了游戏引擎自带的profiler外,还有更底层的统计方式,用adb获取内存大小,命令为:

adb shell dumpsys meminfo <应用包名>

  这可以获取到类似下列的列表:

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

  和图形相关的有如下信息:

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的手机获取,只会获取到如下信息:

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等项:



对比上文中的adb命令其中的数值,可以判定这些值是用同一个方法拿到的(KB转MB需要除以1024):


  用左侧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动态库底层有一个池子。

堆栈内存问题

  偶然中发现,在mali设备上,Graphics峰值增长100MB时,堆栈才显示分配了不到20MB,而高通设备上,分配大小显著高于Graphics峰值,怀疑mali设备的统计上,至少有一个有问题。
  所以我将11张ASTC4x4纹理(10个2048每个5.3MB,1个1024 1.3MB,合计54.3MB)打为一个Bundle,在运行时加载bundle并显示渲染包含这些纹理的Cube,查看堆栈的增长情况:



  发现mali设备的堆栈申请大小才不到20MB,而高通上接近80MB,可以断定,mali设备查这里的堆栈是有问题的。
  同时分别查看加载和卸载这50MB纹理的情况,在高通设备上,加载和卸载纹理时,Graphics几乎没有变化,而在adreno设备上,Graphics比加载纹理前多25MB。

其他情况

  同样的示例打了Vulkan包试了试,Graphics释放不全的问题,在mali vk上同样适用,且对vulkan api的调度,会调度到libvulkan.so,然后再调用到底层的libGLES_mali.so,怀疑mali上vk是封装了层gl?
  在adreno上测试,实际api调用是vulkan.adreno.so;结果50多MB的纹理创建,Graphics才增长32MB,且卸载Bundle销毁纹理时,Graphics没有一点下降,不是统计有问题,就是底层有什么机制。

相关文章

网友评论

      本文标题:Android显存profile方法、mali芯片显存占用高的问

      本文链接:https://www.haomeiwen.com/subject/susthjtx.html