我正在尝试优化我的原生 Android 应用程序中的纹理内存消耗。我有两个计数器:第一个是我自己的,每次调用 TexImage 时都会递增:
g_cbTextureMemory += ImageLineBytes(Format, width) * height;
你可能假设 TexImage 为纹理调用了一次,在我的真实代码中,当前图像大小比添加新图像大小减少,如果纹理重新分配,但实际上没有发生重新分配。
第二个来自系统:
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?是统计误差吗? native 堆是否包含纹理内存(似乎是)?或者对于某些格式,Android 的内部格式可能与我发送的不同?例如,R8G8B8 转换为更优化的东西(似乎不是)?可能一切都好,并且有合理的解释?
最佳答案
这里有几个问题。
我假设您通过比较“大小”行得到 22MB 的差异。这是进程总共请求的内存量。有两个因素可以促成此值。
首先,该区域中的许多虚拟页面可能(而且很可能)尚未分配给物理内存。物理分配仅在进程实际引用以前未使用的虚拟页面时发生。在这种情况下,MMU 会导致 CPU 陷入内核,然后内核会找到并分配一个物理页面来支持虚拟页面。因此,进程的大小可能远远超过可用的物理 RAM,即使在没有交换空间的可移植 Android 设备上也是如此,只要这些页面中的大部分从未被引用。
影响进程大小的第二个因素是 C 库(或 Dalvik VM,或任何用户空间内存管理)将请求比应用程序请求的更大的内存块。这样做是出于性能原因,因为可以在不进行系统调用的情况下频繁分配/取消分配小缓冲区。因此,上面的大小参数并不能很好地指示进程实际使用的内存——它只能作为一个粗略的上限。事实上,“已分配”行可以更好地指示应用程序使用的最大内存,因为它跟踪实际引用的页面。
无论如何,据我所知,您通过 glTexImage 发送到 OpenGL 的任何纹理都被复制到一个单独的内存区域。这可能在图形硬件本身上,或者作为内核空间中内核视频驱动程序的一部分。无论哪种方式,使用的纹理内存都不会反射(reflect)在您的应用程序中。
希望对您有所帮助。
关于android - OpenGL ES 纹理内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4659655/