2009-06-11 8 views
56

Solo estoy mirando para jugar con Objective C (escribiendo aplicaciones de juguete para iPhone) y tengo curiosidad sobre el mecanismo subyacente utilizado para enviar mensajes. Tengo una buena comprensión de cómo las funciones virtuales en C++ se implementan generalmente y cuáles son los costos relativos a una llamada al método estático o no virtual, pero no tengo ningún fondo con Obj-C para saber cómo se envían los mensajes. Buscando alrededor encontré this punto de referencia suelto y menciona que los mensajes en caché IMP son más rápidos que las llamadas a funciones virtuales, que a su vez son más rápidos que un mensaje de envío estándar.Mecanismo de envío de mensajes de Objective C

No estoy tratando de optimizar nada, solo obtener una comprensión más profunda de cómo exactamente se envían los mensajes.

  • ¿Cómo se envían los mensajes de Obj-C?
  • ¿Cómo se almacenan los punteros del método de instancia y puede (en general) decir leyendo el código si un mensaje se almacenará en caché?
  • ¿Los métodos de clase son esencialmente los mismos que una función C (o un método de clase estático en C++) o hay algo más para ellos?

Sé que algunas de estas preguntas pueden ser 'implementadas' pero solo hay una implementación que realmente cuenta.

Respuesta

83

¿Cómo se envían los mensajes de Obj-C?

mensajes de Objective-C se envían utilizando la función del tiempo de ejecución objc_msgSend(). Se muestra en la Apple docs, la función toma al menos 2 argumentos: [. Una lista variable de argumentos al mensaje que se envió]

  1. el objeto receptor
  2. El selector del mensaje

Las instancias de una clase tienen un puntero isa, que es un puntero a su objeto de clase. Los selectores de métodos en cada objeto se almacenan en una "tabla" en el objeto de clase, y la función objc_msgSend() sigue el puntero isa al objeto de clase, para encontrar esta tabla, y verifica si el método está en la tabla para la clase . Si no puede encontrarlo, busca el método en la tabla de la superclase de la clase. Si no se encuentra, continúa en el árbol de objetos, hasta que encuentra el método o llega al objeto raíz (NSObject). En este punto, se lanza una excepción.

¿Cómo se almacenan en caché los punteros del método de instancia y, en general, puede decir leyendo el código si se almacenará un mensaje en caché?

de la guía de tiempo de ejecución de Objective-C de Apple en Messaging:

Para acelerar el proceso de mensajería, el sistema de ejecución almacena en caché los selectores y direcciones de los métodos que se utilizan. Hay una memoria caché separada para cada clase, y puede contener selectores para los métodos heredados, así como para los métodos definidos en la clase. Antes de buscar en las tablas de envío, la rutina de mensajes primero verifica la memoria caché de la clase del objeto receptor (bajo la teoría de que un método que se usó una vez probablemente se vuelva a utilizar). Si el selector de métodos está en la memoria caché, la mensajería es solo un poco más lenta que una llamada a función.Una vez que un programa ha estado funcionando lo suficiente como para "calentar" sus cachés, casi todos los mensajes que envía encuentran un método en caché. Los cachés crecen dinámicamente para acomodar nuevos mensajes a medida que se ejecuta el programa.

Como se ha indicado, el almacenamiento en caché comienza a ocurrir una vez que el programa se está ejecutando, y después de que el programa ha estado funcionando el tiempo suficiente, la mayoría de las llamadas de método se ejecutará a través del método de caché. Como también dice, el almacenamiento en caché ocurre cuando se usan los métodos, por lo que un mensaje solo se almacena en caché cuando se usa.

¿Los métodos de clase son esencialmente los mismos que una función C (o un método de clase estático en C++), o hay algo más para ellos?

Los objetos de la clase manejan el envío del método de una manera similar a la de las instancias de las clases. Cada objeto de clase tiene un objeto que almacena sus propios métodos de clase , en un objeto llamado metaclass. El objeto de clase tiene su propio puntero isa a su objeto de metaclase, que a su vez tiene objetos de súper metaclase, de los que puede heredar objetos de clase. Método de envío a métodos de clase es tan así:

  1. El sistema de despacho sigue isa puntero de la clase de objeto para el objeto metaclase
  2. tabla el método del objeto metaclase se busca para el método de clase.
  3. Si no se encuentra, la búsqueda continúa a la superclase del objeto de metaclase, donde continúa la búsqueda.
  4. Este proceso se repite hasta que se encuentra el método, o hasta que llega a la metaclase raíz, y se lanza una excepción.
+7

excelente explicación. Me parece que comprender el sistema de despacho dinámico y cómo están involucrados los selectores también explica bastante bien por qué los nombres de los métodos deben ser únicos, y Objective-C no admite los métodos sobrecargados de la misma manera que lo hacen Java y C++. Como el selector se almacena en caché como un entero, cualquier método con el mismo nombre se correlacionará con el mismo selector. Para bien o para mal, obliga a los programadores a pensar más acerca de cómo nombrar correctamente los métodos. –

+4

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

+1

¿Qué pasa con el especial 'forward' y ' métodos performv '? ¿Cuándo se llaman? –

19

También escribí una instrucción dada por la guía de instrucciones para objc_msgSend() en x86_64 en mi weblog, si alguien quiere sumergirse profundamente:

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

+3

¡Gran artículo (s)! +1 – jweyrich

+1

Lectura interesante. "Tenga en cuenta que el selector es una cadena C, pero los selectores también son únicos, lo que permite que la búsqueda de caché simplemente compare la dirección de la cadena". Entiendo esto en un solo proceso, pero ¿cómo se logra esto a través de los límites del módulo? –

+2

@DwayneRobinson Hay una fase de 'arreglo' realizada por dyld como cargas ejecutables que resuelve y normaliza todos esos datos comunes. No recuerdo los detalles y, francamente, probablemente hayan cambiado desde la última vez que lo vi. La fuente para el tiempo de ejecución y dyld está disponible aquí http://www.opensource.apple.com. Interesante lee. – bbum

Cuestiones relacionadas