gpt4 book ai didi

swift - 什么是 objc_msgSend,为什么它会占用这么多处理时间?

转载 作者:可可西里 更新时间:2023-10-31 23:59:58 26 4
gpt4 key购买 nike

我一直在分析我的回合制游戏应用程序,我遇到了一个有趣的(也许)问题。根据下图,objc_msgSend 似乎占用了我的应用程序将近一分钟的运行时间。这是什么,它是否是某些代码编写不当的标志?谢谢!

enter image description here

最佳答案

正如@user1118321 上面所说,objc_msgSend 基本上是Objective-C 消息派发的实现。基本上,当您发送诸如 [foo bar] 之类的消息时,objc_msgSend 会被调用,它实际上是这样做的:

  1. 弄清楚 foo 是什么类。

  2. bar 消息(转换为基于字符串的选择器)发送到 foo,并获得一个实现(它基本上是一个 C 函数,它接受 foo 和选择器作为它的前两个参数)。这可以在运行时被拦截并以许多粗糙的方式进行操作,这非常酷,但也会产生性能成本。此外,选择器操作涉及字符串操作,这会产生自身的性能成本。

  3. 调用第 2 步的实现。

如果您想深入了解 objc_msgSend 的内部工作原理,这篇文章非常棒:https://www.mikeash.com/pyblog/friday-qa-2012-11-16-lets-build-objc_msgsend.html

无论如何,所有这些显然不会像直接 C 函数调用那样快,但对于大多数情况,objc_msgSend 的开销不足以成为主要问题(该函数本身是用一些非常硬核的手工优化汇编程序编写的,并使用了一堆缓存技术,因此它可能非常接近它可以提供的所有功能的最佳性能)。然而,在某些情况下,objc_msgSend 的性能可能是一个问题,对于这些情况,您可以尽量减少对 Objective-C 调用的使用,如 @user1118321 所说。或者,如果您可以缩小导致问题的特定 Objective-C 方法调用的范围,则可以使用一种称为 IMP 缓存的技术,通过该技术您可以查找一次方法并将其实现保存为 C 函数指针,这然后您可以根据需要重复调​​用,将对象和选择器作为前两个参数发送。

例如,如果你有这个对象:

@interface Foo: NSObject

- (id)doSomethingWithString:(NSString *)bar;

@end

你可以像这样得到它的IMP:

Foo *foo = ...
SEL selector = @selector(doSomethingWithString:);
IMP imp = [foo methodForSelector:selector];
id (*funcVersion)(Foo *, SEL, NSString *) = (id (*)(Foo *, SEL, NSString *))imp;

您可以将funcVersion 和选择器存储在某处,然后像这样调用它。这样做不会产生 objc_msgSend 的成本,因为您将有效地跳过上面列表中的前两个步骤。

id returnValue = funcVersion(foo, selector, @"Baz");

关于swift - 什么是 objc_msgSend,为什么它会占用这么多处理时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47965127/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com