iOS 纹理占用 33% 的额外内存

发布于 2025-01-08 13:45:22 字数 1794 浏览 0 评论 0原文

我正在测试我的 iOS 游戏,注意到它占用的内存量和它认为应该占用的内存量之间存在差异。最终我将问题范围缩小到纹理占用的内存比我想象的要多 33%。

例如,我认为 256x256 未压缩的 32 位纹理应占用 256*256*4 字节 = 256k。但是,我会注意到,在分配 256x256 纹理时,应用程序的内存会增加 340k 左右。就好像设备分配了足够的内存来存储纹理及其所有 mipmap,但我没有使用 mip 贴图或以任何方式请求空间。

这种额外的内存很引人注目,因为它只会发生在某些设备上。我在 iPod Touch 4 上测试游戏时注意到了额外的内存。但是,在 iPhone 3GS、iPod 3G 或 iPad 1 上没有出现该问题。

设备上的操作系统版本是:

iPod 3G - iOS 3.1.2 (7D11) iPhone 3GS - iOS 4.3.5 (8L1) iPod 4 - iOS 4.2.1 (8C148) iPad - iOS 4.3 (8F190)

编辑

这里有更多信息。我像这样测量应用程序的内存

int PlatformIOS::GetProcessMemUsage()
{
    task_basic_info info;
    mach_msg_type_number_t size = sizeof( info );
    kern_return_t kerr = task_info( mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size );
    if ( kerr == KERN_SUCCESS ) 
        return info.resident_size;

    return 0;
}

这返回的值与您在 Real Mem 的 Instruments 程序中看到的值相同。它实际上非常有用。

这是我分配纹理的方式:

bool GL3DTextureDataPiece::CreateTextureSurface(X3DInterfaceImpl *theInterface, int theWidth, int theHeight, PixelFormat theFormat, RefCount *thePalette, bool generateMipMap)
{
    glGenTextures(1,&mTexture);
    theInterface->SetCurTexture(this);

    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,mLinearFilter?GL_LINEAR:GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,mLinearFilter?GL_LINEAR:GL_NEAREST);

    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, theWidth, theHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

    return true;
}

都是非常基本的东西。唯一让我首先发现内存问题的是不同设备之间的差异。事实上,正是应用程序总内存和资源内存(我自己跟踪图像和声音内存)之间的差异促使我调查发现了这个错误。

I was testing my iOS game and noticed a discrepancy between how much memory it was taking up and how much it thought it should be taking up. Eventually I narrowed down the problem to textures taking 33% more memory than I thought they should be taking.

For instance, I would think a 256x256 uncompressed 32-bit texture should take 256*256*4 bytes = 256k. However, I would notice the app's memory grow by something like 340k when allocating a 256x256 texture. It was as if the device were allocating enough memory to store the texture and all of its mipmaps, but I'm not using mip maps or asking for the space in any way.

This extra memory stood out, because it would only happen on certain devices. I noticed the extra memory when testing the game on an iPod Touch 4. However, the problem didn't occur on an iPhone 3GS, iPod 3G, or iPad 1.

The os versions on the devices are:

iPod 3G - iOS 3.1.2 (7D11)
iPhone 3GS - iOS 4.3.5 (8L1)
iPod 4 - iOS 4.2.1 (8C148)
iPad - iOS 4.3 (8F190)

EDIT

Here's a little more info. I measure the app's memory like this

int PlatformIOS::GetProcessMemUsage()
{
    task_basic_info info;
    mach_msg_type_number_t size = sizeof( info );
    kern_return_t kerr = task_info( mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size );
    if ( kerr == KERN_SUCCESS ) 
        return info.resident_size;

    return 0;
}

This returns the same value that you will see in the Insturments program for Real Mem. It's actually very useful.

And here's how I allocate my textures:

bool GL3DTextureDataPiece::CreateTextureSurface(X3DInterfaceImpl *theInterface, int theWidth, int theHeight, PixelFormat theFormat, RefCount *thePalette, bool generateMipMap)
{
    glGenTextures(1,&mTexture);
    theInterface->SetCurTexture(this);

    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,mLinearFilter?GL_LINEAR:GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,mLinearFilter?GL_LINEAR:GL_NEAREST);

    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, theWidth, theHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

    return true;
}

It's all very basic stuff. The only thing that led me to find the memory problems in the first place was the discrepancy between different devices. In fact, it was the discrepancy between total app memory and resource memory (I track images and sound memory myself) that made me investigate to find this bug.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

策马西风 2025-01-15 13:45:22

我已经找到了解决方法,所以我要回答我自己的问题。但我想我应该发布这个,因为它似乎是一个需要注意的重要信息。

其他人也发现了这个错误。例如,请参见此处:

http://www.cocos2d-iphone.org/forum/topic/29121

好消息是该错误有解决方法。解决方法是仅使用非 2 的幂 (npot) 纹理。 NPOT 纹理无法进行 mip 映射,因此 iOS 不会尝试分配额外的 mip 贴图内存(至少这是它工作原理的理论。)

幸运的是,这在我的引擎中很容易做到,因为它已经将图像划分为如有必要,可以使用多个纹理,以适应 2 的幂纹理,而不使用太多内存。因此,我只是调整了我的代码,不将图像划分为 2 的幂纹理,并进一步强制任何在两个维度上恰好都是 2 的幂的图像加载到比 2 的幂大 1 像素的纹理中。必要的宽度。例如,我会将 256x256 图像放入 257x256 纹理中。

这消除了 33% 的额外内存增长。

请注意,旧设备(例如 iPod 3G)无法执行 npot 纹理,因此在执行此修复之前检查其是否可行非常重要。要检查这一点,您可以查询 GL_APPLE_texture_2D_limited_npot 扩展。另外,在添加此额外像素以强制纹理为 npot 时,请注意不要超过最大纹理大小。

I found a workaround already, so I'm going to answer my own question. But I thought I'd post this because it seems to be an important piece of information to be aware of.

Other people have found this bug. For instance, see here:

http://www.cocos2d-iphone.org/forum/topic/29121

The good news is that there's a workaround for the bug. The workaround is to only use non-power-of-2 (npot) textures. NPOT textures can not be mip mapped so iOS doesn't try to allocate the extra mip map memory (at least that's the theory of why it works.)

Fortunately, this was easy to do in my engine, since it already divides images up into multiple textures if necessary just to fit into power-of-2 textures without using too much memory. So, I just tweaked my code to not divide up images to fit into power-of-2 textures, and further to force any image that happened to be a power of 2 in both dimensions to load into a texture that was 1 pixel bigger than necessary in width. So, for instance, I would put a 256x256 image into a 257x256 texture.

This eliminated the 33% extra memory growth.

Note that older devices such as the iPod 3G can't do npot textures so it's important to check whether its possible before doing this fix. To check for this you can query the GL_APPLE_texture_2D_limited_npot extension. Also, be careful not to exceed the maximum texture size in adding this extra pixel to force the texture to be npot.

拥醉 2025-01-15 13:45:22

确保您没有自动生成 mipmap:
http://www.opengl.org/wiki/Texture#Automatic_mipmap_ Generation

mipmap 链将需要 33% 的额外空间,因为 mipmap 链大约需要额外的 1/3 - 请参阅下面的系列,其中 t 是原始纹理的大小:
= t + t/4 + t/16 + t/64 等...

编辑:

请注意,发布用于测量应用程序内存的方法以及用于创建纹理的方法也会有所帮助。

可能是您使用的方法总是创建额外的 33% 缓冲区,或者您可能只是错误地调用了该方法。

Make sure you're not automatically generating mipmaps:
http://www.opengl.org/wiki/Texture#Automatic_mipmap_generation

The mipmap chain will take 33% extra space, as the mipmap chain approximates 1/3 extra - see the below series where t is the size of the original texture:
= t + t/4 + t/16 + t/64 etc...

EDIT:

Note it would be also helpful to post the method you used to measure the app's memory, and what method you used to create the texture.

It could be that the method you used always creates an extra 33% buffer, or you may be just calling the method incorrectly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文