通过向类添加类别来影响性能

时间:2009-08-24 15:41:09

标签: objective-c cocoa performance

我是Cocoa的新手,在我开始使用类别之前有一个小问题。

假设您向NSString添加一个新方法。这是否会影响正常NSString消息的性能,还是仅在方法调用与标准方法集不匹配时才检查类别方法?

3 个答案:

答案 0 :(得分:8)

所有方法都是使用动态调度发送的,对于类别方法的消息不会干扰“正常”消息。

从性能方面来看,运行时会处理方法与相关类的关联,因此有一次性成本,但每个单独的对象没有变化。我不会关注类别的性能,而是要确保通过类别添加的方法不包括默认方法或其他类别中指定的方法。这就是问题通常开始的地方。

答案 1 :(得分:7)

一般来说,没有。

objc_msgSend()在每个类的基础上保留最近SELIMP个查找的伪最近最近使用缓存。与往常一样,细节是“实现私有细节”,但无论选择器的数量多少,可以合理地说查找时间平均为〜O(1)。最常见的方法是使用小型哈希表 - 如果选择器位于缓存中,则调度基本上是即时的。如果选择器不在缓存中,那么它需要执行“慢速路径”昂贵的查找。

然而,即使是“慢速路径”也可以相当快。可以转向的任何数量的数据结构,例如红黑树,提供出色的子指数查找时间,无论选择器的数量如何,都可以很好地扩展 - 通常在O(log2(selectorCount))范围内。同样,libobjc如何处理这些类型的细节是私有的,但是有很多数据结构可以轻松扩展,无论要搜索的项目数量是多少,都没有理由这种事情甚至应该在您的雷达上。

通过nm进行的快速检查显示,基金会中有7771个选择器,AppKit中有27510个选择器,两者之间共有35281个选择器。投入QuickTime,CoreData,WebKit,Quartz,您可轻松获得50K选择器。 log2查询时间增长率加倍,选择器数量加倍会使最坏情况时间增加不到10%。

总结:objc_msgSend()使用基于哈希的小缓存为最近使用的选择器提供O(1)查找时间......并且存在非常高的时间局部性,因此绝大多数无论系统中存在多少选择器,调度都在O(1)时间内完成。缓存的自然效果是根据您的特定使用模式“调整”自身。即使在高速缓存未命中,也可能是一个合理的猜测,最坏的情况查找时间是〜O(log2(selectorCount))绑定,这是非常好的,并且它可能比实际中更好。

为了它的价值,我花了很多时间调整代码以提高速度。即使是多线程的东西,我把所有的CPU都做了大量的分析 - > NSView / OpenGL重结果渲染,都是在Objective-C中编码的,我只会看到objc_msgSend()在用Shark.app进行分析时占用了1-4%的CPU ......这是最糟糕的情况,进行大量的Objective-C消息调度。这对我来说从来都不是问题,无论是什么样的速度惩罚,都可以轻松地实现100X编程效率。

另见:

Mulle kybernetiK- Obj-C Optimization: The faster objc_msgSend
Objective-C 2.0 Runtime Programming Guide - Messaging
Apple Objective-C Runtime - objc4-437.tar.gz

编辑:这有多奇怪:Patent 5960197 - Compiler dispatch function for object-oriented C。不能说我知道整个Obj-C消息调度系统已获得专利....我猜你真的可以获得任何专利。宝贝,我打算对这个字母表申请专利并收取大笔费用!

答案 2 :(得分:4)

如果你是Cocoa的新手,这不应该是你担心的事情。除了没有剖析而没有对绩效做出假设的基本规则。

如果您需要提供功能,请尽可能添加。如果扩展一个类是有意义的,那么这样做。如果您不向NSString添加功能,则必须在其他地方提供。如果你在另一个类中进行,那么会增加不同的复杂程度。

就个人而言,我会担心你的应用程序的设计。如果有意义,请使用类别,如果您真的关心性能,请在应用程序运行后对其进行分析。

虽然我在这里做了一个假设,但我会说你的应用程序的性能更有可能比调用NSString的速度更快。除非你正在进行一次很多的NSString调用 - 在这种情况下我们会再次回归分析。