2011-06-07 9 views
229

En las plataformas Mac e iOS, las fugas de memoria a menudo son causadas por punteros inéditos. Tradicionalmente, siempre ha sido de suma importancia verificar sus allocs, copias y retenciones para asegurarse de que cada uno tenga su correspondiente mensaje de lanzamiento.¿Qué tipo de fugas evita o minimiza el recuento automático de referencias en Objective-C?

La cadena de herramientas que viene con Xcode 4.2 introduce el recuento automático de referencias (ARC) con la última versión del LLVM compiler, que elimina por completo este problema al hacer que el compilador administre sus cosas por usted. Eso es genial, y reduce un montón de tiempo de desarrollo innecesario y mundano y evita una gran cantidad de pérdidas de memoria descuidadas que son fáciles de solucionar con un equilibrio adecuado de retención/liberación. Incluso los grupos de autorelease deben administrarse de forma diferente cuando habilite ARC para sus aplicaciones Mac e iOS (ya que no debe asignar sus propios NSAutoreleasePool s).

Pero lo demás fugas de memoria no lo hace prevenir que todavía tengo que tener en cuenta?

Como una ventaja adicional, ¿cuáles son las diferencias entre ARC en Mac OS X e iOS y la recolección de basura en Mac OS X?

Respuesta

257

El principal problema relacionado con la memoria que aún deberá tener en cuenta es retener los ciclos. Esto ocurre cuando un objeto tiene un puntero fuerte a otro, pero el objeto objetivo tiene un puntero fuerte hacia el original. Incluso cuando se eliminan todas las demás referencias a estos objetos, aún se conservarán entre sí y no se liberarán. Esto también puede ocurrir indirectamente, mediante una cadena de objetos que podría tener el último en la cadena que hace referencia a un objeto anterior.

Es por esta razón que existen los calificadores de propiedad __unsafe_unretained y __weak. El primero no retendrá ningún objeto al que apunte, pero deja abierta la posibilidad de que ese objeto se vaya y señale a la mala memoria, mientras que el último no retiene el objeto y automáticamente se establece en cero cuando su objetivo es desasignado. De los dos, __weak es generalmente preferido en las plataformas que lo soportan.

Utilizaría estos calificadores para cosas como delegados, donde no desea que el objeto retenga su delegado y potencialmente conduzca a un ciclo.

Otro par de preocupaciones importantes relacionadas con la memoria son el manejo de los objetos Core Foundation y la memoria asignada usando malloc() para tipos como char*. ARC no administra estos tipos, solo objetos Objective-C, por lo que aún tendrá que lidiar con ellos usted mismo. Los tipos de Fundamentos básicos pueden ser particularmente complicados, porque a veces deben enlazarse para coincidir con objetos Objective-C, y viceversa. Esto significa que el control debe transferirse de ARC hacia adelante y hacia atrás cuando se realiza un puente entre los tipos de CF y Objective-C. Algunas palabras clave relacionadas con este puente se han agregado, y Mike Ash tiene una gran descripción de varios casos de puente en his lengthy ARC writeup.

Además de esto, hay varios otros casos menos frecuentes, pero aún potencialmente problemáticos, que el published specification entra en detalle.

Gran parte del nuevo comportamiento, basado en mantener objetos alrededor mientras haya un puntero fuerte para ellos, es muy similar a la recolección de basura en la Mac. Sin embargo, los fundamentos técnicos son muy diferentes. En lugar de tener un proceso de recolector de basura que se ejecuta a intervalos regulares para limpiar objetos que ya no se apuntan, este estilo de administración de la memoria se basa en las reglas rígidas de retención/liberación que todos debemos obedecer en Objective-C.

ARC simplemente toma las tareas de administración de memoria repetitivas que hemos tenido que hacer durante años y las descarga al compilador para que no tengamos que preocuparnos por ellas nuevamente. De esta forma, no tiene los problemas de detención o los perfiles de memoria de diente de sierra experimentados en las plataformas recolectadas. He experimentado ambos en mis aplicaciones de Mac recolectadas con basura, y estoy ansioso por ver cómo se comportan bajo ARC.

Para obtener más información sobre la recolección de basura en comparación con ARC, consulte this very interesting response by Chris Lattner on the Objective-C mailing list, donde enumera muchas ventajas de ARC sobre la recolección de basura Objective-C 2.0. Me encontré con varios de los problemas de GC que describe.

+2

Gracias por el detalle respuesta. Tuve el mismo problema cuando definí un delegado en _unsafe_unretained y obtuve mi aplicación bloqueada, más tarde lo solucioné cambiando a fuerte pero ahora tiene una pérdida de memoria. Entonces, lo cambié a débil y funciona como un encanto. – chathuram

+0

@ichathura ¡Guau! Me salvaste del mio ARC. Me encontré con el mismo bloqueo al usar CMPopTipView. – Nianliang

+0

@BradLarson: "no tiene los problemas de detención o los perfiles de memoria de diente de sierra experimentados en las plataformas recolectadas de basura". Esperaría que los perfiles de memoria de diente de sierra y de detención empeoraran por la recuperación basada en el alcance y el rendimiento mucho peor del recuento de referencias, por lo que me gustaría ver una comparación real. –

14

ARC no lo ayudará con la memoria que no es de ObjC; por ejemplo, si tiene malloc() algo, aún necesita free().

ARC puede ser engañado por performSelector: si el compilador no puede determinar qué es el selector (el compilador generará una advertencia al respecto).

ARC también generará código siguiendo las convenciones de nomenclatura ObjC, por lo que si mezcla código ARC y MRC puede obtener resultados sorprendentes si el código MRC no hace lo que el compilador cree que prometen los nombres.

0

ARC tampoco gestionará los tipos de CoreFoundation. Puede 'puentearlos' (usando CFBridgingRelease()) pero solo si va a usarlo como un objeto Objective-C/Cocoa. Tenga en cuenta que CFBridgingRelease solo disminuye el CoreFoundation retenga el conteo por 1 y lo mueve a Objective-C's ARC.

4

que experimentaron pérdidas de memoria en mi solicitud por los siguientes 4 temas:

  1. que no invalida NSTimers al despedir a los controladores de vista
  2. El olvido de quitar cualquier observadores a NSNotificationCenter al despedir el controlador de vista.
  3. manteniendo fuertes referencias a uno mismo en bloques.
  4. Usando fuertes referencias a los delegados a la vista de propiedades del controlador

Por suerte me encontré con la siguiente entrada en el blog y fue capaz de corregirlos: http://www.reigndesign.com/blog/debugging-retain-cycles-in-objective-c-four-likely-culprits/

Cuestiones relacionadas