Saltar al contenido

¿Cómo funciona el nuevo mecanismo de recuento automático de referencias?

Nuestros programadores estrellas agotaron sus reservas de café, en su búsqueda diariamente por la resolución, hasta que Ariana halló el hallazgo en Gitea por lo tanto en este momento la compartimos con nosotros.

Solución:

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

Con Clang Static Analyzer, 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.

El conteo automático de referencias (ARC) es el siguiente paso lógico. Si el compilador puede reconocer dónde debería 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 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 la memoria en estas plataformas. Describo el problema principal a tener en cuenta (retener ciclos) en mi respuesta aquí, que puede requerir un poco de pensamiento de su parte para marcar punteros 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 ofrece lo mejor de ambos mundos al eliminar la necesidad de escribir código de retención / liberación, pero sin tener los perfiles de memoria de detención y diente de sierra que se ven en un entorno de recolección de basura. Las únicas ventajas que tiene la recolección de basura sobre esto son su capacidad para lidiar con los ciclos de retención y el hecho de que las asignaciones de propiedades atómicas son económicas (como se discutió 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 estar orientado 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 impulsa este esfuerzo en LLVM, Objective-C será lo primero a menos que otra parte comprometa importantes recursos propios para esto.

La presentación de esto sorprendió a los desarrolladores en la WWDC, por lo que la gente no sabía que se podía hacer algo como esto. Puede aparecer en otras plataformas con el tiempo, pero por ahora es exclusivo de LLVM y Objective-C.

ARC es simplemente reproducir viejo retener / liberar (MRC) con el compilador averiguando cuándo llamar a retener / liberar. Tiende a tener un mayor rendimiento, un menor uso máximo de memoria 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.

Por ejemplo, si tiene una clase llamada nodo y el nodo tiene un NSArray de hijos y una única referencia a su padre que “simplemente funciona” con GC. Con ARC (y también el recuento de referencias manual) tiene un problema. Se hará referencia a cualquier nodo dado desde sus hijos y también desde su padre.

Igual que:

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

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

Cuando haya terminado con él (y B1 / B2 / B3), un sistema GC eventualmente decidirá mirar todo lo que pueda encontrar a partir de la pila y los registros de la 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 referencia de 3 (B1, B2 y B3 hacen referencia a él), y B1 / B2 / B3 tendrán todos un recuento de referencia de 1 (el NSArray de A tiene una referencia a cada). Entonces, todos esos objetos permanecen vivos a pesar de que nada puede 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 aferra 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 lo hará) evaporarse, 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.

Por lo tanto, ARC se enfoca en el mismo tipo de problemas que se enfoca en GC. Sin embargo, ARC funciona en un conjunto más limitado de patrones de uso que GC, por lo que si tomara un lenguaje GC (como Java) e injertara 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 una mayor prioridad al rendimiento (o tal vez la previsibilidad) mientras que GC le da una 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 algunos patrones de uso (¡válidos!) Se derrumbará y morirá.

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 los objetos por 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 lanzar cosas tan pronto como ya no sean necesarias, en lugar de lanzarlas a un grupo de liberación automática simplemente por convenciones.

Algunas otras mejoras incluyen la reducción a cero de las referencias débiles, la copia automática de bloques al montón, aceleraciones en todos los ámbitos (¡6x 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.

valoraciones y reseñas

Te invitamos a corroborar nuestra publicación añadiendo un comentario y puntuándolo te damos la bienvenida.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *