¿Cómo funciona el nuevo mecanismo de conteo automático de referencia?

206

¿Alguien puede explicarme brevemente cómo funciona ARC? Sé que es diferente de Garbage Collection, pero me preguntaba exactamente cómo funcionaba.

Además, si ARC hace lo que hace GC sin obstaculizar el rendimiento, ¿por qué Java usa GC? ¿Por qué no usa ARC también?

usuario635064
fuente
2
Esto le dirá todo al respecto: http://clang.llvm.org/docs/AutomaticReferenceCounting.html Cómo se implementa en Xcode e iOS 5 está bajo NDA.
Morten Fast
14
@mbehan Eso es un mal consejo. No quiero iniciar sesión o incluso tener una cuenta para el centro de desarrollo de iOS, pero de todos modos estoy interesado en conocer ARC.
Andres F.
1
ARC no hace todo lo que hace GC, requiere que trabaje con semántica de referencia fuerte y débil explícitamente, y pierde memoria si no lo hace bien. En mi experiencia, esto es al principio complicado cuando usas bloques en Objective-C, e incluso después de que aprendes los trucos, te queda un código repetitivo molesto (IMO) alrededor de muchos usos de bloques. Es más conveniente olvidarse de las referencias fuertes / débiles. Además, GC puede funcionar algo mejor que ARC wrt. CPU, pero requiere más memoria. Puede ser más rápido que la administración de memoria explícita cuando tiene mucha memoria.
TaylanUB
@TaylanUB: "requiere más memoria". Mucha gente dice eso, pero me cuesta creerlo.
Jon Harrop
2
@ JonHarrop: Actualmente, ni siquiera recuerdo por qué dije eso, para ser honesto. :-) Mientras tanto, me di cuenta de que hay tantas estrategias de GC diferentes que tales declaraciones generales probablemente no valen nada. Permítanme recitar Hans Boehm de sus Mitos y medias verdades de asignación de memoria : "¿Por qué esta área es tan propensa a dudosas sabidurías populares?"
TaylanUB

Respuestas:

244

Cada nuevo desarrollador que viene a Objective-C tiene que aprender las reglas rígidas de cuándo retener, liberar y liberar objetos. Estas reglas incluso especifican convenciones de nomenclatura que implican el recuento retenido de objetos devueltos por los métodos. La gestión de la memoria en Objective-C se convierte en una segunda naturaleza una vez que toma en serio estas reglas y las aplica de manera consistente, pero incluso los desarrolladores de Cocoa más experimentados se equivocan de vez en cuando.

Con el Analizador estático de Clang, los desarrolladores de LLVM se dieron cuenta de que estas reglas eran lo suficientemente confiables como para poder construir una herramienta para señalar fugas de memoria y liberaciones excesivas dentro de las rutas que toma su código.

Conteo automático de referencia (ARC) es el siguiente paso lógico. Si el compilador puede reconocer dónde debe retener y liberar objetos, ¿por qué no hacer que inserte ese código por usted? Las tareas rígidas y repetitivas son en lo que los compiladores y sus hermanos son excelentes. Los humanos olvidan las cosas y cometen errores, pero las computadoras son mucho más consistentes.

Sin embargo, esto no lo libera por completo de preocuparse por la administración de memoria en estas plataformas. Describo el problema principal a tener en cuenta (retener ciclos) en mi respuesta aquí , lo que puede requerir un poco de reflexión por su parte para marcar indicadores débiles. Sin embargo, eso es menor en comparación con lo que está ganando en ARC.

En comparación con la gestión de memoria manual y la recolección de basura, ARC le brinda lo mejor de ambos mundos al eliminar la necesidad de escribir código de retención / liberación, sin tener los perfiles de detención y memoria de diente de sierra en un entorno de recolección de basura. Las únicas ventajas que tiene la recolección de basura sobre esto son su capacidad para manejar los ciclos de retención y el hecho de que las asignaciones de propiedades atómicas son económicas (como se discute aquí ). Sé que estoy reemplazando todo mi código Mac GC existente con implementaciones ARC.

En cuanto a si esto podría extenderse a otros idiomas, parece orientado en torno al sistema de conteo de referencias en Objective-C. Puede ser difícil aplicar esto a Java u otros lenguajes, pero no sé lo suficiente sobre los detalles del compilador de bajo nivel para hacer una declaración definitiva allí. Dado que Apple es quien está impulsando este esfuerzo en LLVM, Objective-C vendrá primero a menos que otra parte comprometa importantes recursos propios para esto.

La presentación de estos desarrolladores sorprendidos en WWDC, por lo que la gente no sabía que algo así podría hacerse. Puede aparecer en otras plataformas con el tiempo, pero por ahora es exclusivo de LLVM y Objective-C.

Brad Larson
fuente
56
énfasis mío: esto no lo libera por completo de preocuparse por la administración de la memoria
bshirley
66
¿ARC es realmente una innovación? De su respuesta, concluyo que ARC es un concepto nuevo, que se utiliza en Objective-C por primera vez (corríjame si me equivoco). Para ser honesto, no soy un desarrollador de Objective-C y no sé mucho sobre ARC, pero ¿los Boost Shared Pointers (vea boost.org) no son exactamente lo mismo? Y si no lo son, ¿cuál es la diferencia?
theDmi
2
@DMM: en lugar de depender de operadores sobrecargados (como lo hace Boost), este es un proceso a nivel de compilador, que lo extiende a todo el lenguaje. Entre otras cosas, esto facilita la conversión de una aplicación contada manualmente de referencia a ARC. Boost también podría manejar variables locales de manera diferente a ARC, donde ARC sabe el momento en que una variable local ya no se usa y puede lanzar en ese punto. Creo que con Boost todavía necesita especificar de alguna manera que haya terminado con la variable.
Brad Larson
66
Para responder a la pregunta "¿es nuevo?", Delphi ha tenido un conteo automático de referencias para cadenas, matrices e interfaces (para soporte COM) durante más de una década. Estoy de acuerdo en que realmente es un buen compromiso entre un entorno gc'd y un entorno "hacerlo todo manualmente". Me alegro de que esté en ObjC y LLVM (para que otros idiomas también puedan aprovecharlo).
davidmw
2
@theDmi: "¿ARC es realmente una innovación?". El recuento automático de referencias se inventó en 1960 y se ha utilizado en muchos idiomas, como Python y Mathematica. No se usa en JVM o CLR porque es muy lento y presenta fugas.
Jon Harrop
25

ARC es solo jugar retención / liberación antigua (MRC) con el compilador averiguando cuándo llamar a retención / liberación. Tiende a tener un mayor rendimiento, menor uso de memoria pico y un rendimiento más predecible que un sistema GC.

Por otro lado, algunos tipos de estructura de datos no son posibles con ARC (o MRC), mientras que GC puede manejarlos.

Como ejemplo, si tiene una clase llamada nodo, y el nodo tiene una matriz NSA de elementos secundarios, y una única referencia a su elemento primario que "simplemente funciona" con GC. Con ARC (y el conteo manual de referencias también) tiene un problema. Se hará referencia a cualquier nodo dado desde sus elementos secundarios y también desde su elemento primario.

Me gusta:

A -> [B1, B2, B3]
B1 -> A, B2 -> A, B3 -> A

Todo está bien mientras usa A (digamos a través de una variable local).

Cuando haya terminado con él (y B1 / B2 / B3), un sistema GC finalmente decidirá mirar todo lo que pueda encontrar a partir de los registros de pila y CPU. Nunca encontrará A, B1, B2, B3, por lo que los finalizará y reciclará la memoria en otros objetos.

Cuando usa ARC o MRC, y termina con A, tiene un recuento de 3 (B1, B2 y B3 todos lo referencian), y B1 / B2 / B3 tendrán un recuento de referencia de 1 (NSArray de A tiene una referencia a cada). Por lo tanto, todos esos objetos permanecen vivos aunque nada pueda usarlos.

La solución común es decidir que una de esas referencias debe ser débil (no contribuir al recuento de referencias). Eso funcionará para algunos patrones de uso, por ejemplo, si hace referencia a B1 / B2 / B3 solo a través de A. Sin embargo, en otros patrones falla. Por ejemplo, si a veces se aferrará a B1 y espera volver a subir a través del puntero principal y encontrar A. Con una referencia débil si solo se aferra a B1, A puede (y normalmente) se evaporará y tomará B2 y B3 con eso.

A veces esto no es un problema, pero algunas formas muy útiles y naturales de trabajar con estructuras complejas de datos son muy difíciles de usar con ARC / MRC.

Entonces, ARC apunta al mismo tipo de problemas que los objetivos de GC. Sin embargo, ARC funciona en un conjunto de patrones de uso más limitado que GC, por lo que si toma un lenguaje GC (como Java) e injerta algo como ARC en él, algunos programas ya no funcionarían (o al menos generarían toneladas de memoria abandonada , y puede causar serios problemas de intercambio o quedarse sin memoria o espacio de intercambio).

También puede decir que ARC le da mayor prioridad al rendimiento (o tal vez a la previsibilidad) mientras que GC le da mayor prioridad a ser una solución genérica. Como resultado, GC tiene demandas de CPU / memoria menos predecibles y un rendimiento más bajo (normalmente) que ARC, pero puede manejar cualquier patrón de uso. ARC funcionará mucho mejor para muchos patrones de uso comunes, pero para unos pocos (¡válidos!) Patrones de uso se caerá y morirá.

Rayas
fuente
"Por otro lado, algunos tipos de estructura de datos no son posibles con ARC" Creo que usted quiso decir que la limpieza automática no es posible sin sugerencias; obviamente, las estructuras de datos son.
Steven Fisher
Claro, pero SOLO la limpieza automática de los objetos ObjC está disponible en ARC, por lo que "sin limpieza automática" == "sin limpieza". Sin embargo, reformularé y responderé cuando tenga más tiempo.
Stripes
@Stripes: el equivalente de la limpieza manual en ARC es la interrupción manual de los ciclos, por ejemplo foo = nil.
Douglas
"[ARC] tenderá a tener un mayor rendimiento ... ARC otorga una mayor prioridad al rendimiento". Me sorprende leer eso cuando es bien sabido que el conteo de referencias es mucho más lento que el rastreo de recolección de basura. flyingfrogblog.blogspot.co.uk/2011/01/…
Jon Harrop
2
En teoría, GC es más rápido (cada manipulación de recuento de referencia debe ser coherente en la memoria caché multiprocesador, y hay muchas de ellas). En la práctica, el único sistema GC disponible para ObjC es mucho más lento. También es muy común que los sistemas de GC para hacer una pausa hilos en momentos aleatorios para el usuario cantidades perceptibles de tiempo (hay algunos sistemas en tiempo real de GC, pero no son comunes, y creo que tienen limitaciones "interesantes")
Rayas
4

magia

Pero más específicamente, ARC funciona haciendo exactamente lo que haría con su código (con ciertas diferencias menores). ARC es una tecnología de tiempo de compilación, a diferencia de GC, que es tiempo de ejecución y afectará negativamente su rendimiento. ARC rastreará las referencias a objetos para usted y sintetizará los métodos de retención / liberación / liberación automática de acuerdo con las reglas normales. Debido a esto, ARC también puede liberar cosas tan pronto como ya no se necesiten, en lugar de arrojarlas a un grupo de liberación automática solo por el bien de la convención.

Algunas otras mejoras incluyen la reducción a cero de referencias débiles, la copia automática de bloques en el montón, las aceleraciones en todos los ámbitos (6 veces para grupos de liberación automática)

Una discusión más detallada sobre cómo funciona todo esto se encuentra en LLVM Docs en ARC.

Joshua Weinberg
fuente
2
-1 "ARC es una tecnología de tiempo de compilación, a diferencia de GC, que es tiempo de ejecución y afectará negativamente su rendimiento". Los recuentos de referencia se superan en tiempo de ejecución, lo cual es muy ineficiente. Es por eso que el rastreo de GC como JVM y .NET es mucho más rápido.
Jon Harrop
1
@ Jon: ¿Tienes una prueba de esto? Según mi propia lectura, parece que los nuevos algoritmos RC generalmente funcionan tan bien o mejor que M&S GC.
xryl669
1
@ xryl669: hay una explicación completa en el Manual de GC ( gchandbook.org ). Tenga en cuenta que el seguimiento! = M&S.
Jon Harrop
3

Varía mucho de la recolección de basura. ¿Has visto las advertencias que te dicen que puedes estar filtrando objetos en diferentes líneas? Esas declaraciones incluso le dicen en qué línea asignó el objeto. Esto se ha llevado un paso más allá y ahora puede insertar retain/ releasedeclaraciones en las ubicaciones adecuadas, mejor que la mayoría de los programadores, casi el 100% del tiempo. Ocasionalmente, hay algunos casos extraños de objetos retenidos con los que necesita ayudar.

FreeAsInBeer
fuente
0

Muy bien explicado por la documentación del desarrollador de Apple. Lea "Cómo funciona ARC"

Para asegurarse de que las instancias no desaparezcan mientras aún son necesarias, ARC rastrea cuántas propiedades, constantes y variables se refieren actualmente a cada instancia de clase. ARC no desasignará una instancia mientras exista al menos una referencia activa a esa instancia.

Para asegurarse de que las instancias no desaparezcan mientras aún son necesarias, ARC rastrea cuántas propiedades, constantes y variables se refieren actualmente a cada instancia de clase. ARC no desasignará una instancia mientras exista al menos una referencia activa a esa instancia.

Conocer a Diff. entre la recolección de basura y ARC: Lea esto

Lalit Kumar
fuente
0

ARC es una característica del compilador que proporciona administración automática de memoria de objetos.

En lugar de tener que recordar cuándo usarlo retain, release, autoreleaseARC evalúa los requisitos de vida útil de sus objetos e inserta automáticamente las llamadas de administración de memoria adecuadas para usted en el momento de la compilación. El compilador también genera los métodos dealloc adecuados para usted.

El compilador inserta las retain/releasellamadas necesarias en tiempo de compilación, pero esas llamadas se ejecutan en tiempo de ejecución, como cualquier otro código.

El siguiente diagrama le dará una mejor comprensión de cómo funciona ARC.

ingrese la descripción de la imagen aquí

Aquellos que son nuevos en el desarrollo de iOS y no tienen experiencia laboral en el Objetivo C. Consulte la documentación de Apple para la Guía de programación de administración avanzada de memoria para una mejor comprensión de la administración de memoria.

revs Yogesh Bharate
fuente