替换iOS上的系统分配器以获取乐趣和收益

分配器是所有应用程序性能中鲜为人知但非常重要的一部分。 通过为您的应用选择其他分配器,可以潜在地提高其性能和内存使用率。 您可以使用下面概述的方法替换您的分配器。

分配器是用于在堆上分配和释放内存的函数的集合。 在包括iOS在内的大多数平台上,都会有一个默认的平台,它具有分配内存的功能( malloc )和释放内存的功能( free )。

似乎在堆上分配和取消分配内存是一个简单且已解决的问题,但实际上根本不是。 Facebook报告说,使用其他分配器代替系统的默认分配器时,Web服务器的吞吐量增加了一倍以上。 通过使用其他分配器,Ruby基准测试得到了11%的加速。 通过仅泄漏内存而不是释放内存,I​​nstagram Web服务器的速度提高了10%。

CPU影响

您创建的几乎每个Objective-C对象(以及至少一些Swift类实例)都将需要一个或多个堆分配,因为对象存储在堆中。 这意味着分配器可能会影响CPU,因为对它的调用数量之多以及它所做的所有簿记工作。

对性能的另一个影响是非常微妙的,但影响很大,它决定从堆中分配每个内存的位置。 详细信息超出了本文的范围。

记忆影响

由于碎片,簿记等原因,所有分配器至少需要一点内存开销(如果不是很多的话)。 这是一个不幸的情况,它影响了Ruby Web服务器,他们不得不从内置分配器(malloc)切换到另一个分配器(jemalloc):

我们可以看到,例如,Javascript引擎至少有两个,而CFNetwork至少有一个。 还有更多不被该断点捕获的内容。

公平地说,这不是使应用程序更快运行的第一件事。 仅在以下情况下才应尝试:

  • 您已经解决了所有性能低下的问题
  • 您监视高层性能指标,例如应用程序启动时间,您可以查看这些指标以分析其他分配器的有效性
  • 您具有良好的内部测试,因此任何与此有关的稳定性问题都将在生产之前被发现。

上图中的大量分配器可以看出,每种情况都没有完美的分配器。 好的分配器可让您调整各种折衷方案,例如内存使用量与CPU使用量。 您的应用程序有其自己独特的工作负载,可能会受益于其他分配器。

有很多分配器,有很多方法可以对其进行调整,但是目前最受欢迎的第三方是jemalloc ,它由Facebook支持,用于FreeBSD和Mozilla等大型项目。 这是一个很好的起点,也是我在本文中设置的供我们使用的起点。

邪恶但有效的功能替换方式

替换分配器的最彻底的方法是使用我们自己的方法来替代Apple的常规分配机制。 一个立即想到的方法是混淆+alloc+dealloc ,但是我们将不加+dealloc地保留所有分配(例如,构成很大一部分的C和C ++分配)。 相反,我们可以使用一种称为dyld interposition的技术,以便每当尝试调用mallocfree等时,它都会调用我们的函数。 Objective-C和C ++调用了这些较低级的函数,因此也涵盖了这些情况。 您可以在此处获取以下代码:

https://github.com/michaeleisel/jemalloc

将动态(非静态)库放入应用程序后,您可以通过运行单元测试来验证malloc是否已成功替换(请参见“测试”部分)。

警告:尽管没有明显的问题,但尚未在生产中得到证明。 有关它的稳定性以及如何安全的更多详细信息,请参见回购的“稳定性”部分。 测试您自己的应用程序的性能,然后确定风险是否值得。

它还可能破坏与malloc混乱的调试工具,例如Guard Malloc或Address Sanitizer。

注意,有很多方法可以替换malloc 。 另一个方法是弄乱malloc区域,如该文件所示。

CFAllocator邪恶程度较低但效率较低的方法

CFAllocator是代表分配器的结构,例如,它具有mallocfree实现的函数指针。 苹果将​​它用于很多事情,例如分配NSString或NSArray使用的缓冲区。 您可以通过创建自己的CFAllocator并调用CFAllocatorSetDefault来设置Apple使用的默认值。 理想情况下,您应该在应用程序生命周期的早期进行此操作以捕获更多分配。 尽管它不能像以前那样涵盖所有情况,但至少得到了Apple的正式支持,因此更加安全。 这是jemalloc的CFAllocator。 您可以使用上面的repo来构建jemalloc,并添加--no-replace标志,以便您可以自己进行替换。

微基准测试,例如测试调用mallocfree所需的时间,几乎是没有用的。 分配太复杂,无法像这样进行测试。 相反,请查看应用程序的高级性能指标,例如启动时间。

现在,您有几种方法可以自己替换默认分配器。 看看是否有帮助! 交换系统分配器是其他平台上的常见做法,并且很高兴在iOS上看到它。 苹果的分配器可能是最适合您的分配器,但是通过使用这些方法,您可以自己探索分配器。