【问题标题】:objective-c: is method calling inside a class still with selectors or pure calls?Objective-c:类内部的方法调用仍然使用选择器还是纯调用?
【发布时间】:2011-10-06 18:23:27
【问题描述】:

我正在比较不同的编程语言和开发平台。 Objective-c 和其他语言的一个重要区别是它使用选择器、消息,所以每次都调用 objc_msgSend,跨越共享库的边界,因此引入了可测量的开销,加上 objc_msgSend 的更多开销(在缓存的情况下很少)内部运作,就像这里解释的那样: http://www.mulle-kybernetik.com/artikel/Optimization/opti-3.html 我不是专家,所以我必须相信这篇文章,在这个论坛上找到。 在 Apple 官方指南中,我发现“点语法”只是“语法糖”,即使用了相同的方法调用机制。 问题:我想知道,如果在类实例中执行纯调用,那么调用 objc_msgSend 将是一种浪费。也就是从同一个类实例的方法调用一个类实例的方法。 谢谢

【问题讨论】:

    标签: objective-c methods overhead


    【解决方案1】:

    所有 Objective-C 方法调用都使用 obj_msgSend。这是因为代码不知道实际的真实类self。即:它可以是具有另一个实现的子类,甚至可以是远程机器通过 xmlrpc 实现的方法的代理。

    AFAIK 如果您知道要经常向对象 Y 发送消息 X,您可以通过获取给定对象的选择器的实现来自己优化。

    【讨论】:

    • 你指的是IMP吗?为班级内的每个电话做这件事真是一团糟。但是编译器不能理解实例在编译时调用自己吗?很奇怪。我的意思是,我不必使用选择器语法来调用同一实例的方法,是吗?
    • @P5music :即使在 C++ 中,从类的成员函数的实现内部对类的虚方法的调用也会通过虚函数表。在 Objective-C 中,每个方法调用都是虚拟的。所以它通过objc_msgSend 设施调用。别担心,Apple 知道 objc_msgSend 绝对是至关重要的,所以他们付出了很多努力来调整它,使用手写的汇编和大量的技巧。
    【解决方案2】:

    在假设的 OOP 语言中考虑这种情况:

    class A {
         say_something(){
             print("A!")
         }
         do_something(){
             say_something()
         }
    }
    

    class B : extends A {
         say_something(){
             print("B!")
         }
    }
    

    现在假设您有一个B 的实例,并调用do_something

    B b;
    b.do_something();
    

    应该b 打印A 还是B?如果在do_something 的实现中对say_something 的调用通过vtable(在C++ 中)或obj_msgSend(在Obj-C 中),它将打印B,但如果编译器决定调用同一个类中的方法应该调用同一个类中的方法,它会打印A

    哪个是可取的取决于具体情况。因此,在 C++ 中,您可以选择是否标记成员函数 virtual。 在 Objective-C 中,每个方法都是虚拟的。

    因此,即使在 C++ 中,您建议的优化也不会针对虚拟方法进行。我不会说没有虚拟方法的语言是正确的 OOP 语言。

    无论如何,现在您可能会担心它会降低 Obj-C 应用程序的性能。苹果知道危险,所以他们有很多很多的优化。例如,在最近的运行时中,objc_msgSend 位于固定地址,因此您无需首先通过共享库边界。

    Mulle-Kybernetic 的文章也很不错,但请注意它已经过时了:它是十年前的事了,这在这个行业是史前时代。您可以在bbum's blog postsHamster's blog posts 中阅读有关objc_msgSend 实现的最新优化。

    如果您正在编写管理 UI 的代码,则使用标准消息传递(即幕后 objc_msgSend)就足够了。它甚至在移动设备上运行非常流畅!因此,不要通过获取IMP 等来进行过早的优化,直到在测量代码性能后证明是绝对必要的。

    如果您正在编写一个计算密集型代码,例如涉及数以万计的粒子移动,是的,我建议您不要使用 Obj-C 消息传递框架。在这种情况下,只需简单地编写一个 C 代码(可以在 Objective-C 中使用)或 C++ 代码(可以在 Objective-C++ 中使用)。

    【讨论】:

      【解决方案3】:

      它仍然通过 objc_msgSend 和变体使用动态调度。

      理想情况下,将为 objc 类型生成类似于 JIT 的内容。

      与 objc 不同,c++ 编译器可以使用静态调度来调用标记为虚拟的 c++ 类型当它可以确定类型时

      无论如何,有很多方法可以优化——你可以从用 c++ 实现开始,然后在真正方便的地方使用 objc……但我不确定你到底想要完成什么。

      【讨论】:

        猜你喜欢
        • 2012-12-12
        • 2013-12-23
        • 1970-01-01
        • 2012-02-09
        • 2017-06-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多