我正在尝试优化原生Android应用程序中的纹理内存消耗。我有两个计数器:第一个是我自己的,每次TexImage调用时都会增加:
g_cbTextureMemory += ImageLineBytes(Format, width) * height;
您可以假设TexImage为纹理调用了一次,在我的实际代码中,当前图像大小的减少比添加new,如果纹理重新分配,但实际上没有重新分配。
其次来自系统:
adb shell dumpsys meminfo my.app.name
它提供了这样的东西:
** MEMINFO in pid 3269 [my.app.name] **
native dalvik other total
size: 39320[*] 6663 N/A 45983
allocated: 21453 3945 N/A 25398
free: 34 2718 N/A 2752
(Pss): 6281 3078 40643 50002
(shared dirty): 2240 4968 12108 19316
(priv dirty): 6232 2684 17948 26864
之后我执行以下操作:将所有纹理替换为1x1(通过将伪1x1图像发送到glTexImage)。我看到meminfo给出了另一个结果,并且22Mb上的单元格[*]发生了变化。但是我的计数器显示我有25Mb的纹理,所以我希望有25Mb。
那么在转储纹理内存消耗隐藏在哪里?需要明确的是,对于1x1纹理转储是: ** MEMINFO in pid 3269 [my.app.name] **
native dalvik other total
size: 16892 5575 N/A 22467
allocated: 13211 3574 N/A 16785
free: 208 2001 N/A 2209
(Pss): 6273 3122 17016 26411
(shared dirty): 2252 5032 10756 18040
(priv dirty): 6224 2588 5848 14660
为什么我没有得到25Mb?是统计错误吗?本机堆是否包含纹理内存(似乎是)?或者对于某些格式Android可能有不同于我发送的内部格式?例如,R8G8B8转化为更优化的东西(似乎不是)?可能一切都好,还有理性的解释吗?
答案 0 :(得分:2)
这里有几个问题。
我假设您通过比较'尺寸'线获得22MB的差异。这是进程总共请求的内存量。有两个因素可以促成这个价值。
首先,可能(并且可能)该区域中的许多虚拟页面尚未分配给物理内存。仅当进程实际引用先前未使用的虚拟页面时才会发生物理分配。在这种情况下,MMU使CPU陷入内核,然后内核找到并分配一个物理页面来支持虚拟页面。因此,即使在没有交换空间的便携式Android设备上,进程的大小也可能远远超过可用的物理RAM,只要大多数页面永远不会被引用。
可影响进程大小的第二个因素是C库(或Dalvik VM或任何用户空间内存管理)将以比应用程序请求更大的块请求内存。这是出于性能原因而完成的,因为频繁分配/解除分配小缓冲区可以在不进行系统调用的情况下完成。因此,上面的size参数不能很好地指示进程使用的实际内存 - 它只能用作粗略的上限。实际上,“已分配”行可以更好地指示应用程序使用的最大内存,因为它会跟踪实际引用的页面。
无论如何,据我所知,通过glTexImage发送到OpenGL的任何纹理都会被复制到一个单独的内存区域。这可能在图形硬件本身上,也可能在内核空间中作为内核视频驱动程序的一部分。无论哪种方式,使用的纹理内存都不会反映在您的应用程序中。
希望有所帮助。