我只是在玩Objective (编写玩具iPhone应用程序),我很好奇用来发送消息的底层机制。我非常了解C++中的虚拟函数是如何实现的,以及与静态或非虚拟方法调用相关的成本,但我不了解Obj是如何发送消息的。在浏览时,我发现这是一个松散的基准测试,它提到IMP缓存的消息比虚拟函数调用更快,而虚拟函数调用又比标准消息发送更快。
我没有试图优化任何东西,只是更深入地了解消息是如何被发送的。
我知道其中一些问题可能是“实现依赖的”,但是只有一个实现是真正重要的。
发布于 2009-06-11 17:05:39
如何发送Obj消息?
Objective消息是使用运行时的objc_msgSend()函数发送的。如苹果文档所示,该函数至少包含2个参数:
类的实例有一个isa指针,它是指向其类对象的指针。每个对象中的方法选择器存储在类对象中的“表”中,objc_msgSend()函数遵循指向类对象的isa指针,查找此表,并检查方法是否在类的表中。如果它找不到它,它将在类的超类的表中查找方法。如果未找到,则继续在对象树上运行,直到找到方法或获取根对象(NSObject)为止。此时,将引发异常。
实例方法指针是如何被缓存的,您(通常)如何通过读取代码来判断消息是否会被缓存?
摘自苹果公司关于消息传递的Objective运行时指南
为了加快消息传递过程,运行时系统缓存方法的选择器和地址。每个类都有一个单独的缓存,它可以包含继承方法和类中定义的方法的选择器。在搜索分派表之前,消息传递例程首先检查接收对象类的缓存(理论是可能再次使用曾经使用过的方法)。如果方法选择器在缓存中,则消息传递仅略慢于函数调用。一旦一个程序运行足够长的时间来“预热”它的缓存,它发送的几乎所有消息都会找到一个缓存的方法。当程序运行时,缓存动态增长以容纳新消息。
如前所述,缓存在程序运行后就开始发生,并且在程序运行足够长时间之后,大多数方法调用都将通过缓存的方法运行。正如它还指出的,缓存是在使用方法时发生的,因此只有在使用消息时才会缓存消息。
是类方法,本质上与C函数(或C++中的静态类方法)相同,或者它们还有更多的东西吗?
类对象以类似于类实例的方式处理方法发送。每个类对象都有一个对象,它将自己的类方法存储在一个名为metaclass的对象中。类对象有自己的元类对象的isa指针,而元类对象又有超级元类对象,可以从这些对象继承类对象。方法分派到类方法如下:
isa指针发布于 2021-12-03 17:53:12
调度机制
它用于在调用方法(发送消息)时找到必要的可执行代码。
InlineStatic(Direct)(C,Java final,C++ default,Swift static,final) -编译器知道在编译时实现必要的方法。Dynamic -是基于witness table(虚拟表,调度表)的,并引入了多态性。Table,V- table (C++ virtual,Java,Swift默认值)--每个对象都有一个类的引用,它有一个具有所有方法地址的表(超级、重写、新的)。SIL包含vtable或witness_tableMessage(object,Swift dynamic) -每个对象都有一个对类的引用(Isa),其中包含对超类和调度表E 232的引用(它只包含已实现的方法(新的和开销的)),而不包含来自Super的方法。如果在当前调度表中没有找到方法,则继续在超类的调度表中搜索。通过缓存优化了这个过程。SIL包含volatile目标-C消息分发例如
class A {
func foo1() {}
func foo2() {}
}
class B: A {
override func foo2() {}
func foo3() {}
}
目标C obc_msgSend
id obc_msgSend(id self, SEL op, ...)
// self - object which receive a message
// op - selector of method
//... - arguments如果没有为给定的选择器找到方法实现,则会看到下一个错误。
unrecognized selector sent to instancehttps://stackoverflow.com/questions/982116
复制相似问题