¿Qué tipo de fugas hace el recuento automático de references en Objective-C no evitar o minimizar?

En las plataforms Mac y iOS, las pérdidas de memory a menudo son causadas por pointers inéditos. Tradicionalmente, siempre ha sido de sum importancia verificar sus asignaciones, copys y retenidos para asegurarse de que cada uno tenga un post de publicación correspondiente.

La cadena de herramientas que viene con Xcode 4.2 introduce el recuento automático de references (ARC) con la última versión del comstackdor LLVM , que elimina totalmente este problema al hacer que el comstackdor administre tus cosas por usted. Eso es genial, y networkinguce mucho el time de desarrollo innecesario y mundano e impide muchas memory leaks descuidadas que son fáciles de arreglar con un equilibrio adecuado de retención / liberación. Incluso las agrupaciones autorelease deben administrarse de forma diferente cuando habilita ARC para sus aplicaciones Mac y iOS (ya que no debería asignar sus propias NSAutoreleasePool ).

Pero, ¿qué otra pérdida de memory no evita que todavía tenga que estar pendiente?

Como 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?

El principal problema relacionado con la memory del que aún debe tener en count es retener ciclos. Esto ocurre cuando un object tiene un puntero fuerte a otro, pero el object de destino tiene un puntero fuerte de vuelta al original. Incluso cuando todas las demás references a estos objects se eliminan, aún se aferran entre sí y no se liberarán. Esto también puede suceder indirectamente, por una cadena de objects que podrían tener el último de la cadena que se refiere a un object anterior.

Es por esta razón que existen los calificadores de propiedad __unsafe_unretained y __weak . El primero no retiene ningún object al que apunta, pero deja abierta la posibilidad de que ese object se vaya y apunte a una mala memory, mientras que este último no retiene el object y automáticamente se pone a cero cuando su objective es desasignado. De los dos, generalmente se prefiere __weak en las plataforms que lo soportan.

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

Otro par de preocupaciones importantes relacionadas con la memory son el event handling los objects Core Foundation y la memory asignada usando malloc() para types como char* . ARC no gestiona estos types, solo los objects Objective-C, por lo que también deberá tratarlos usted mismo. Los types de base de núcleo pueden ser particularmente complicados, porque a veces tienen que superponerse para hacer coincidir los objects de Objective-C, y viceversa. Esto significa que el control debe transferirse hacia adelante y hacia atrás desde ARC cuando se puentean entre los types de CF y Objective-C. Se agregaron algunas palabras key relacionadas con este puente y Mike Ash tiene una excelente descripción de varios casos de puente en su extensiva escritura de ARC .

Además de esto, hay varios otros casos less frecuentes, pero aún potencialmente problemáticos, que se detallan en las especificaciones publicadas .

Gran parte del nuevo comportamiento, basado en mantener objects alnetworkingedor siempre que haya un puntero fuerte para ellos, es muy similar a la recolección de elementos no utilizados en Mac. Sin embargo, los apuntalamientos técnicos son muy diferentes. En lugar de tener un process de recolección de elementos no utilizados que se ejecuta a intervalos regulares para limpiar objects que ya no se señalan, este estilo de administración de memory depende de 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 memory repetitiva que tuvimos que hacer durante años y las descarga al comstackdor para que nunca tengamos que preocuparnos por ellas nuevamente. De esta manera, no tiene los problemas vacilantes ni los perfiles de memory en diente de sierra experimentados en las plataforms recolectadas de basura. He experimentado estos dos problemas en mis aplicaciones recolectadas de Mac, y estoy ansioso por ver cómo se comportan en ARC.

Para más información sobre la recolección de basura vs. ARC, vea esta muy interesante respuesta de Chris Lattner en la list de correo de Objective-C , donde enumera muchas ventajas de ARC sobre la recogida de basura Objective-C 2.0. Me he encontrado con varios de los problemas GC que describe.

ARC no lo ayudará con la memory que no sea ObjC, por ejemplo, si malloc() algo, todavía necesita free() .

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

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

Experimenté filtraciones de memory en mi aplicación debido a los siguientes 4 problemas:

  1. No invalidando NSTimers al descartar controlleres de vista
  2. Olvidando eliminar cualquier observador en NSNotificationCenter al descartar el controller de vista.
  3. Mantener fuertes references a sí mismo en bloques.
  4. Uso de references fuertes a los delegates en las properties del controller de vista.

Afortunadamente encontré la siguiente publicación del blog y pude corregirlos: http://www.reigndesign.com/blog/debugging-retain-cycles-in-objective-c-four-likely-culprits/

ARC tampoco administrará los types de CoreFoundation. Puede 'puentear' (usando CFBridgingRelease() ) pero solo si va a usarlo como object Objective-C / Cocoa. Tenga en count que CFBridgingRelease simplemente decrementa que CoreFoundation retenga el conteo por 1 y lo mueva al ARC de Objective-C.