Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 目标C消息调度机制_Objective C_Performance - Fatal编程技术网

Objective c 目标C消息调度机制

Objective c 目标C消息调度机制,objective-c,performance,Objective C,Performance,我只是开始玩Objective C(编写玩具iPhone应用程序),我很好奇用于发送消息的底层机制。我对C++中的虚函数一般如何实现以及相对于静态或非虚方法调用的成本有着很好的理解,但是我没有任何Obj-C的背景来知道消息是如何发送的。浏览一下,我发现了松散的基准测试,它提到IMP缓存消息比虚拟函数调用快,虚拟函数调用又比标准消息发送快 我并没有试图优化任何东西,只是更深入地了解消息是如何被发送的 Obj-C消息是如何发送的 实例方法指针是如何被缓存的,您(通常)可以通过读取代码来判断消息是否

我只是开始玩Objective C(编写玩具iPhone应用程序),我很好奇用于发送消息的底层机制。我对C++中的虚函数一般如何实现以及相对于静态或非虚方法调用的成本有着很好的理解,但是我没有任何Obj-C的背景来知道消息是如何发送的。浏览一下,我发现了松散的基准测试,它提到IMP缓存消息比虚拟函数调用快,虚拟函数调用又比标准消息发送快

我并没有试图优化任何东西,只是更深入地了解消息是如何被发送的

  • Obj-C消息是如何发送的
  • 实例方法指针是如何被缓存的,您(通常)可以通过读取代码来判断消息是否会被缓存
  • 类方法本质上与C函数(或C++中的静态类方法)相同吗?或者它们还有什么不同

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

Obj-C消息是如何发送的?

Objective-C消息使用运行时的
objc\u msgSend()
函数进行调度。如中所示,该函数至少接受2个参数:

  • 接收对象
  • 消息的选择器
  • [发送消息的参数的可变列表。]
  • 类的实例有一个
    isa
    指针,它是指向其类对象的指针。每个对象中方法的选择器存储在类对象中的“表”中,并且
    objc_msgSend()
    函数跟随指向类对象的
    isa
    指针,以查找该表,并检查该方法是否在该类的表中。如果找不到,则在类的超类的表中查找该方法。如果未找到,它将继续向上移动对象树,直到找到方法或到达根对象(
    NSObject
    )。此时,将抛出一个异常

    实例方法指针是如何缓存的,您(通常)能通过阅读代码判断消息是否会被缓存吗?

    摘自苹果的Objective-C运行时指南:

    为了加快消息传递过程,运行时系统会在方法使用时缓存它们的选择器和地址。每个类都有一个单独的缓存,它可以包含继承方法以及类中定义的方法的选择器。在搜索分派表之前,消息传递例程首先检查接收对象类的缓存(理论上,曾经使用过的方法可能会再次使用)。如果方法选择器在缓存中,则消息传递只比函数调用稍微慢一点。一旦一个程序运行足够长的时间来“预热”它的缓存,它发送的几乎所有消息都会找到一个缓存方法。缓存动态增长,以适应程序运行时的新消息

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

    类方法本质上与C函数(或C++中的静态类方法)相同吗?或者它们还有什么不同吗?

    类对象以类似于类实例的方式处理方法分派。每个类对象都有一个对象,该对象在一个名为
    元类的对象中存储自己的类方法。类对象有自己的
    isa
    指向其元类对象的指针,而元类对象又有超级元类对象,它可以从超级元类对象继承类对象。对类方法的方法分派如下:

  • 分派系统遵循类对象的
    isa
    指针指向元类对象
  • 在元类对象的方法表中搜索类方法
  • 如果未找到,搜索将继续到元类对象的超类,搜索将继续
  • 这个过程会重复,直到找到该方法,或者直到它到达根元类并引发异常为止

  • 我还在我的博客上为x86_64上的objc_msgSend()编写了一个逐条指令指南,如果有人想深入研究:


    很好的解释。我发现理解动态调度系统以及如何选择选择器也解释了为什么方法名称必须是唯一的,Objto-C不支持以java和C++相同的方式重载方法。因为选择器被缓存为整数,所以任何具有相同名称的方法都会映射到相同的选择器。不管是好是坏,它确实迫使程序员更多地考虑正确的命名方法。。。特殊的“前进”和“执行”方法如何?什么时候叫?读起来很有趣。“请注意,选择器是一个C字符串,但选择器也是唯一的,因此允许缓存查找简单地比较字符串地址。”我在一个进程中得到这个,但这是如何跨模块边界实现的?@DwayneRobinson dyld执行了一个“修复”阶段,作为一个可执行加载来解析和规范所有此类公共数据。我不记得细节了,坦率地说,自从我上次查看以来,它们可能已经改变了。此处提供了运行时和dyld的源代码。有趣的阅读。