响应 iOS 中的 RAM 可用性

Posted

技术标签:

【中文标题】响应 iOS 中的 RAM 可用性【英文标题】:Responding to RAM availability in iOS 【发布时间】:2011-12-23 09:00:46 【问题描述】:

我有一个纹理密集的 OpenGL 游戏,我想根据设备的 RAM 大小对其进行调整。最高分辨率的纹理我在 iPhone 4 或 iPad2 上运行良好,但早期的设备在加载纹理的过程中崩溃。我有这些纹理的低分辨率版本,但我需要知道何时使用它们。

我目前的策略是检测特定的旧设备(3GS 有一个低分辨率屏幕;iPad 没有摄像头),然后只加载 iPad2 及更高版本和 iPhone 4 及更高版本的高分辨率纹理 - 我想我'需要为 iPod touch 做点什么。但我更愿意使用特征检测而不是硬编码设备模型,因为模型检测对于 API 和硬件的未来变化是脆弱的。

我正在考虑的另一种可能性是首先加载高分辨率纹理,然后在我收到低内存警告时将其删除并替换为低分辨率。但是,我不确定我是否有机会做出回应;我注意到应用程序经常在调试控制台上出现任何通知之前就死机了。

如何检测我正在运行的设备是否没有足够的 RAM 来加载我的纹理的高分辨率版本?

退一步说,我可以使用其他一些特定于 OpenGL 纹理内存的自适应技术吗?

注意事项:

    我已经打开和关闭 SO 搜索与可用 RAM 检测相关的答案,但它们基本上都建议分析内存使用情况并消除浪费(最小化临时对象的生命周期,以及所有这些废话)。我已经尽可能多地这样做了,我无法将高分辨率纹理压缩到旧设备中。

    PVRTC 不是一个选项。纹理包含片段着色器使用的数据,并且必须以无损格式存储。

【问题讨论】:

请注意,您可以获得总 ram 和免费 ram 统计信息,详见此线程 free memory on ios。另外,我在我的 iPhone 4 上测试了代码,它运行良好! 【参考方案1】:

要获取设备的总(最大)物理 RAM,请使用 [NSProcessInfo processInfo].physicalMemory

见Documentation。

【讨论】:

【参考方案2】:

总物理 RAM 可通过 sysctl() 获得,如 this blog post 中所述,并实现为干净的 API here(请参阅相应 .m 文件中 totalMemory 的实现)。

为了方便和后代,我已经解除了博客的代码:

#include <sys/sysctl.h>

size_t phys_mem()

 int mib[] =  CTL_HW, HW_PHYSMEM ;
 size_t mem;
 size_t len = sizeof(mem);
 sysctl(mib, 2, &mem, &len, NULL, 0);
 return mem;

我不知道 Apple 是否会批准以这种方式使用 sysctl() 的应用。它已记录在案,但仅适用于 Mac OS X。

【讨论】:

你有没有在 App Store 应用中获得批准? @Nate:是的。 Your World 在大于 384 MB 的设备上加载 96 兆像素的地球;否则,它会退回到 24 兆像素版本。这个数字没有什么特别之处。它只是在可以的设备和不能的设备之间的一半。 只要使用[NSProcessInfo processInfo].physicalMemory +1 @史蒂夫。为什么我第一次问这个问题时没有人指出这一点?如果您将此添加为答案,我会将绿色勾号切换到它。【参考方案3】:

在这种情况下,对于内存管理,您需要了解的最重要的一点是是使用高分辨率纹理还是使用低分辨率纹理。我使用的最简单的方法是检查这个

CGFloat scale = [[UIScreen mainScreen] scale];
if ((scale > 1.0) || (self.view.frame.size.width > 320)) 
        highRes = TRUE;

到目前为止,这适用于所有设备,并且应该是未来的证明,较新的设备将使用高分辨率。 您也可以在此处计算纵横比(稍后在 ipad 与 iphone 上有所帮助)

aspect = self.view.frame.size.width/self.view.frame.size.width

不要先加载高分辨率,它会浪费你的应用程序加载时间,在我的 3G 上,我的大部分启动都花在加载(即使是低分辨率)纹理上,只需在开始时测试这一点,不要接触高分辨率的东西.

在旧设备上,由于纹理过大,程序会在没有警告的情况下死掉,这可能与调试器无法捕获视频内存消耗并自行死机有关。

要获得更大的优化,请考虑为 mipmap 着色以检查实际使用的最小纹理大小(仅当您使用 3D 对象时)。

忘记视频 RAM 大小的问题吧,内存实际上是共享的,所以你在争夺系统内存,在旧设备上你有 MB 的使用限制,但它仍然是系统内存。

关于内存管理,有很多方法,最简单的应该是标记已加载的纹理,以及需要的纹理,当内存警告来临时,将已加载但不需要的纹理转储...

【讨论】:

感谢您的详细回复。我不能接受这一点,因为它没有回答如何检测 RAM 而不是使用特征检测的核心问题(或者你是在暗示这是不可能的或不值得追求的?),但 +1 指出scale &gt; 1.0检测 iPhone 4。我没想到。 在不越狱的情况下尝试检测内存的唯一方法是尝试将其全部填充并测量您获得了多少。此外,由于内存与可能正在运行的所有其他应用程序(系统应用程序,如邮件等)共享,即使知道物理内存的数量并不值钱。这就是为什么我说忘记那条路线,这不是您要寻找的坚实基础。 您的措辞含糊不清,我是否应该将视频内存视为独立的,或者放弃测量 RAM。我不关心其他正在运行的应用程序;根据经验,256 MB 的设备总是崩溃,而 512 MB 的设备从不会崩溃。此外,您提议的测试在最新的 iPod Touch(retina & 256 MB)上失败了,这凸显了我对模型检测脆弱性的担忧。顺便说一句,寻找 iPod Touch 问题的解决方案让我找到了一个可能的答案,我将单独发布。【参考方案4】:

据我所知,一个人能做的最重要的三件事是 -

    实现 - (void)didReceiveMemoryWarning 并在 iOS 发送警告 1 和 2 时做出响应。 Instruments 中的配置文件代码试图找到泄漏和更好的 mem 最佳实施方式。 检测设备类型并可能使用该信息。 使用某种形式的纹理压缩(例如 PVRTC)来节省空间。

我认为你正在做大部分事情。问题是人们甚至不知道 iOS 设备有多少 RAM。 Apple 不会发布 iOS 设备的技术规格。

此外,不能假设只有在消耗 100mb 之后才会收到内存警告。 iOS 给出的警告取决于设备的当前状态、正在运行的其他应用程序以及它们消耗的内存量。所以它变得很棘手。

我可以建议 2 个必读部分 - Best Practices for Working with Texture Data 和 Tuning Your OpenGL ES Application

【讨论】:

以上是关于响应 iOS 中的 RAM 可用性的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法确定 Linux 中可用视频 RAM 的数量?

java IO 模型--快速分清 同步|阻塞

从 GRUB2 多重引导信息结构中获取总可用 RAM

为啥 XML 存储在 iOS 中不可用?

用 C 语言 (STM32F4) 估计剩余的可用 RAM

内存映射显示的 RAM 多于物理可用的 RAM