3

我有一个 iOS 应用程序,我认为内存踩踏正在发生。所以我在 Xcode 中打开了 Guard Malloc、Guard Edges 和 Scribble 并运行它来尝试追踪它。但是启用 Guard Malloc 后,事情开始以非常奇怪的方式出错。在某些(可预测的)情况下,视图的背景不会绘制,您可以看到它们背后的视图。如果我进行文件下载,应用程序在下载结束时在主线程上崩溃,堆栈上没有我的代码(除了main),有时控制台中会记录一些图形错误,例如:

<Error>: CGBitmapContextInfoCreate: unable to allocate 201000 bytes for bitmap data
<Error>: CGContextSetInterpolationQuality: invalid context 0x0

其中一些东西(例如CGBitmapContextInfoCreate)在我的代码中的任何地方都没有使用。

记录的最后一件事是这样的:

Failed to VM allocate 262144 bytes
Explicitly trapping into debugger!!!

有没有其他人让 Guard Malloc 导致这些错误?这可能是什么根源?

4

1 回答 1

4

Guard Malloc 通过内存管理单元 (MMU) 工作。MMU 允许您将内存的某些部分标记为允许进程访问,并将某些区域标记为非法——这本质上就是受保护的内存。他们通过将内存划分为单个页面(通常为 4kb)并将相关权限分配给每个页面来做到这一点。他们不能为每个地址单独存储属性,因为这需要大量的存储空间。

引发非法访问异常的是 MMU。

当运行正常代码时,这一切都意味着一些越界访问不会引发异常,因为您的许多数据小于 4kb,因此大部分数据与其他数据共享页面。并且对页面中任何地方的写入都是可以接受的,即使它不是您要写入的数组或者该页面已被新对象重用。

所以 Guard Malloc 给每个对象一个单独的页面。这极大地增加了您的内存占用,因为它将所有对象大小四舍五入到页面大小。这也是影响性能的原因——任何合理的缓存算法都会停止正常运行。

一个副作用是可以使用的存储空间要少得多。假设您有一个NSString通常占用 280 字节的存储空间。那么现在它占据了整个页面。因此,您会更快地耗尽内存。(编辑:根据 Greg 在下面的评论,一旦分配了一个页面,Guard Malloc 就不允许它返回到池中,因此您的内存占用会累积起来,这意味着您几乎可以肯定最终会用完内存,无论给定[几乎]所有对象都在堆上并且返回对象是正常的)

Guard Edges 可以通过在每个分配之间放置空页面来加剧这种情况。因此,每个分配的对象至少会从虚拟内存池中取出一个额外的页面,否则它不会有。如果虚拟池的大小与您的物理池足够接近,这可能会影响您。

CGBitmapContextInfoCreateUIView当被要求更新其内容时,几乎可以肯定您正在使用的标准之一在内部使用。系统不再有足够的内存来满足请求,并且看起来视图没有尝试优雅地处理该结果。

可能唯一有意义的建议是单独尝试调试工具。

于 2013-06-06T23:06:04.673 回答