目标C消息调度机制

我只是盯着目标C(编写玩具iPhone应用程序),我很好奇用于发送消息的基本机制。 我很好的理解了C ++中的虚函数是如何实现的,以及静态或非虚方法调用的代价是什么,但是我没有Obj-C的背景知道如何发送消息。 浏览周围,我发现这个松散的基准,它提到IMPcaching的消息比虚拟函数调用更快,而这又比标准的消息发送更快。

我不是想优化任何东西,只是更深入地了解消息如何发送。

  • 如何调度Obj-C消息?
  • 实例方法指针如何获得caching,并且你能(通常)通过读取代码告诉消息是否会被caching?
  • 类方法与C函数(或C ++中的静态类方法)本质上是相同的,还是有更多的东西?

我知道其中的一些问题可能是“依赖于实现”,但是只有一个实现是真正重要的。

如何调度Obj-C消息?

Objective-C消息使用运行时的objc_msgSend()函数分派。 在Apple文档中显示,该函数至less需要2个参数:

  1. 接收对象
  2. 消息的select器
  3. [正在发送的消息的variables列表。]

一个类的实例有一个isa指针,它是一个指向它们的类对象的指针。 每个对象中方法的select器都存储在类对象的“表”中, objc_msgSend()函数遵循isa指向类对象的指针,查找该表,并检查该方法是否在表中class上。 如果找不到它,它将在类的超类的表中查找该方法。 如果没有find,它继续向上的对象树,直到它find方法或获取到根对象( NSObject )。 在这一点上,抛出了一个exception。

实例方法指针如何获得caching,并且你能(通常)通过读取代码告诉消息是否会被caching?

从苹果的消息传递的Objective-C运行时指南:

为了加速消息处理,运行时系统caching方法的select器和地址。 每个类都有一个单独的caching,它可以包含inheritance方法的select器以及类中定义的方法。 在search调度表之前,消息传递例程首先检查接收对象类的caching(理论上曾经使用过的方法可能会再次使用)。 如果方法select器在caching中,则消息传递仅比函数调用慢一点。 一旦一个程序运行了足够长的时间来“加热”它的caching,它发送的几乎所有消息都会find一个caching的方法。 程序运行时,cachingdynamic增长以适应新的消息。

如上所述,一旦程序运行,caching开始发生,并且在程序运行足够长的时间之后,大多数方法调用将通过caching的方法运行。 正如它所说的那样,caching是在使用方法时发生的,因此只有在使用消息时才会caching消息。

类方法与C函数(或C ++中的静态类方法)本质上是相同的,还是有更多的东西?

类对象以类的实例处理方法派发。 每个类对象都有一个对象,它将自己的方法存储在一个名为metaclass的对象中。 类对象具有自己的isa指向其元类对象,该对象又具有超类元对象,它可以inheritance类对象。 方法派发到类的方法是这样的:

  1. 调度系统遵循类对象的isa指向元类对象的指针
  2. 在元类对象的方法表中search类方法。
  3. 如果没有find,search继续到元类对象的超类,在那里继续search。
  4. 重复此过程,直到find该方法,或者直到它到达根元类为止,并抛出exception。

我也在我的博客上写了x86_64上objc_msgSend()的指令指南,如果有人想深入:

http://www.friday.com/bbum/2009/12/18/objc_msgsend-part-1-the-road-map/