OpenGL ES纹理内存

时间:2011-01-11 16:03:44

标签: android opengl-es

我正在尝试优化原生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转化为更优化的东西(似乎不是)?可能一切都好,还有理性的解释吗?

1 个答案:

答案 0 :(得分:2)

这里有几个问题。

我假设您通过比较'尺寸'线获得22MB的差异。这是进程总共请求的内存量。有两个因素可以促成这个价值。

首先,可能(并且可能)该区域中的许多虚拟页面尚未分配给物理内存。仅当进程实际引用先前未使用的虚拟页面时才会发生物理分配。在这种情况下,MMU使CPU陷入内核,然后内核找到并分配一个物理页面来支持虚拟页面。因此,即使在没有交换空间的便携式Android设备上,进程的大小也可能远远超过可用的物理RAM,只要大多数页面永远不会被引用。

可影响进程大小的第二个因素是C库(或Dalvik VM或任何用户空间内存管理)将以比应用程序请求更大的块请求内存。这是出于性能原因而完成的,因为频繁分配/解除分配小缓冲区可以在不进行系统调用的情况下完成。因此,上面的size参数不能很好地指示进程使用的实际内存 - 它只能用作粗略的上限。实际上,“已分配”行可以更好地指示应用程序使用的最大内存,因为它会跟踪实际引用的页面。

无论如何,据我所知,通过glTexImage发送到OpenGL的任何纹理都会被复制到一个单独的内存区域。这可能在图形硬件本身上,也可能在内核空间中作为内核视频驱动程序的一部分。无论哪种方式,使用的纹理内存都不会反映在您的应用程序中。

希望有所帮助。