Recuento de referencias

ImprimirCitar
Técnica de seguimiento de los recursos de software

En informática, el recuento de referencias es una técnica de programación para almacenar el número de referencias, punteros o identificadores de un recurso, como un objeto, un bloque de memoria, espacio en disco y otros..

En los algoritmos de recolección de elementos no utilizados, los recuentos de referencia se pueden usar para desasignar objetos que ya no se necesitan.

Ventajas y desventajas

La principal ventaja del conteo de referencias sobre la recolección de basura de rastreo es que los objetos se recuperan tan pronto ya no se puede hacer referencia a ellos, y de manera incremental, sin largas pausas para los ciclos de recolección y con Vida útil claramente definida de cada objeto. En aplicaciones en tiempo real o sistemas con memoria limitada, esto es importante para mantener la capacidad de respuesta. El conteo de referencias también se encuentra entre las formas más simples de administración de memoria para implementar. También permite una gestión eficaz de los recursos que no son de memoria, como los objetos del sistema operativo, que a menudo son mucho más escasos que la memoria (los sistemas de recolección de elementos no utilizados de seguimiento utilizan finalizadores para esto, pero la recuperación retrasada puede causar problemas). Los recuentos de referencia ponderados son una buena solución para la recolección de elementos no utilizados en un sistema distribuido.

Ejemplo de lista circular de una tesis maestra de 1985. Rectangles denote cons pares, con recuentos de referencia. Incluso si se elimina el puntero izquierdo entrante, todos los recuentos permanecen.

Los ciclos de recolección de elementos no utilizados de seguimiento se activan con demasiada frecuencia si el conjunto de objetos vivos ocupa la mayor parte de la memoria disponible; requiere espacio adicional para ser eficiente. El rendimiento del recuento de referencias no se deteriora a medida que disminuye la cantidad total de espacio libre.

Los recuentos de referencias también son información útil para usar como entrada para otras optimizaciones de tiempo de ejecución. Por ejemplo, los sistemas que dependen en gran medida de objetos inmutables, como muchos lenguajes de programación funcionales, pueden sufrir una penalización de eficiencia debido a las copias frecuentes. Sin embargo, si el compilador (o el sistema de tiempo de ejecución) sabe que un objeto en particular tiene solo una referencia (como la mayoría en muchos sistemas) y que la referencia se pierde al mismo tiempo que se crea un nuevo objeto similar (como en la cadena append declaración str ← str + "a"), puede reemplazar la operación con una mutación en el objeto original.

El conteo de referencias en forma ingenua tiene tres desventajas principales sobre la recolección de basura de rastreo, las cuales requieren mecanismos adicionales para mejorar:

  • Las actualizaciones frecuentes que implica son una fuente de ineficiencia. Mientras que el rastreo de los recolectores de basura puede afectar la eficiencia severamente a través de fallos de conmutación de contexto y línea de caché, recogen relativamente infrecuentemente, mientras que el acceso a los objetos se hace continuamente. Además, menos importante, el recuento de referencia requiere que cada objeto gestionado por memoria reserve espacio para un recuento de referencia. En el rastreo de los recolectores de basura, esta información se almacena implícitamente en las referencias que se refieren a ese objeto, ahorrando espacio, aunque el rastreo de los recolectores de basura, en particular los incrementales, puede requerir espacio adicional para otros fines.
  • El algoritmo ingenuo descrito anteriormente no puede manejar ciclos de referencia, un objeto que se refiere directa o indirectamente a sí mismo. Un mecanismo que dependa puramente de los recuentos de referencia nunca considerará cadenas cíclicas de objetos para la eliminación, ya que su recuento de referencia está garantizado para permanecer no cero (cf. imagen). Existen métodos para hacer frente a esta cuestión, pero también pueden aumentar la sobrecarga y la complejidad del recuento de referencias, por otra parte, estos métodos sólo deben aplicarse a datos que puedan formar ciclos, a menudo un pequeño subconjunto de todos los datos. Uno de estos métodos es el uso de referencias débiles, mientras que otro implica el uso de un algoritmo de brillo de marca que se llama infrecuentemente para limpiar.
  • En un entorno concurrente, todas las actualizaciones de los recuentos de referencia y todas las modificaciones de puntero deben ser operaciones atómicas, que incurren en un costo adicional. Hay tres razones para los requisitos de atomicidad. En primer lugar, un campo de recuento de referencia puede ser actualizado por varios hilos, y por lo tanto una instrucción atómica adecuada, como un (costly) compare-and-swap, debe ser utilizado para actualizar los conteos. En segundo lugar, debe ser claro qué objeto pierde una referencia para que su recuento de referencia pueda ser decrementado adecuadamente. Pero determinar este objeto no es trivial en un entorno donde múltiples hilos intentan modificar la misma referencia (es decir, cuando las competiciones de datos son posibles). Por último, existe una carrera sutil en la que un hilo gana un puntero a un objeto, pero antes de que aumenta el recuento de referencia del objeto, todas las demás referencias a este objeto se eliminan simultáneamente por otros hilos y el objeto se recupera, haciendo que dicho hilo aumente un recuento de referencia de un objeto reclamado.

Además de esto, si la memoria se asigna desde una lista libre, el recuento de referencias sufre de localidad deficiente. El recuento de referencias por sí solo no puede mover objetos para mejorar el rendimiento de la memoria caché, por lo que los recopiladores de alto rendimiento también implementan un recolector de elementos no utilizados de rastreo. La mayoría de las implementaciones (como las de PHP y Objective-C) tienen un rendimiento de caché deficiente, ya que no implementan la copia de objetos.

Interpretación de gráficos

Cuando se trata de esquemas de recolección de basura, a menudo es útil pensar en el gráfico de referencia, que es un gráfico dirigido donde los vértices son objetos y hay un borde desde un objeto A a un objeto. B si A tiene una referencia a B. También tenemos un vértice o vértices especiales que representan las variables locales y las referencias que tiene el sistema de tiempo de ejecución, y ningún borde llega nunca a estos nodos, aunque los bordes pueden ir de ellos a otros nodos.

En este contexto, el recuento de referencia simple de un objeto es el grado de entrada de su vértice. Eliminar un vértice es como recolectar un objeto. Solo se puede hacer cuando el vértice no tiene aristas entrantes, por lo que no afecta el grado de salida de ningún otro vértice, pero puede afectar el grado de entrada de otros vértices, lo que hace que sus objetos correspondientes también se recopilen si su en-grado también se convierte en 0 como resultado.

El componente conectado que contiene el vértice especial contiene los objetos que no se pueden recopilar, mientras que otros componentes conectados del gráfico solo contienen basura. Si se implementa un algoritmo de recolección de basura de recuento de referencias, cada uno de estos componentes de basura debe contener al menos un ciclo; de lo contrario, se habrían recopilado tan pronto como su recuento de referencia (es decir, el número de bordes entrantes) se redujera a cero.

Lidiar con la ineficiencia de las actualizaciones

Aumentar y disminuir los recuentos de referencias cada vez que se crea o se destruye una referencia puede afectar significativamente el rendimiento. Las operaciones no solo toman tiempo, sino que dañan el rendimiento de la memoria caché y pueden generar burbujas en la canalización. Incluso las operaciones de solo lectura, como calcular la longitud de una lista, requieren una gran cantidad de lecturas y escrituras para actualizaciones de referencias con un recuento de referencias ingenuo.

Una técnica simple es que el compilador combine varias actualizaciones de referencias cercanas en una sola. Esto es especialmente efectivo para las referencias que se crean y se destruyen rápidamente. Sin embargo, se debe tener cuidado de colocar la actualización combinada en la posición correcta para evitar una liberación prematura.

El método Deutsch-Bobrow de recuento de referencias aprovecha el hecho de que la mayoría de las actualizaciones de recuentos de referencias son generadas por referencias almacenadas en variables locales. Ignora estas referencias, solo cuenta las referencias en las estructuras de datos, pero antes de que se pueda eliminar un objeto con un recuento de referencia cero, el sistema debe verificar con un escaneo de la pila y los registros que no existe ninguna otra referencia a él.

Otra técnica ideada por Henry Baker implica incrementos diferidos, en los que las referencias que se almacenan en variables locales no incrementan inmediatamente el recuento de referencias correspondiente, sino que lo difieren hasta que sea necesario. Si dicha referencia se destruye rápidamente, entonces no hay necesidad de actualizar el contador. Esto elimina una gran cantidad de actualizaciones asociadas con referencias de corta duración (como el ejemplo anterior de conteo de longitud de lista). Sin embargo, si dicha referencia se copia en una estructura de datos, entonces el incremento diferido debe realizarse en ese momento. También es fundamental realizar el incremento diferido antes de que el recuento del objeto llegue a cero, para evitar una liberación prematura.

Levanoni y Petrank obtuvieron una disminución espectacular de los gastos generales en las actualizaciones de contadores. Introducen el método de fusión de actualizaciones que fusiona muchas de las actualizaciones de recuento de referencias redundantes. Considere un puntero que en un intervalo dado de la ejecución se actualiza varias veces. Primero apunta a un objeto O1, luego a un objeto O2, y así sucesivamente hasta que al final del intervalo apunta a algún objeto On. Un algoritmo de conteo de referencia normalmente ejecutaría rc(O1)--, rc(O2)++, rc(O2)--, rc(O3)++, rc(O3)--,..., rc(On)++. Pero la mayoría de estas actualizaciones son redundantes. Para que el recuento de referencias se evalúe correctamente al final del intervalo, basta con ejecutar rc(O1)-- y rc(On)++. El resto de las actualizaciones son redundantes.

Levanoni y Petrank demostraron en 2001 cómo usar dicha fusión de actualización en un colector de conteo de referencia. Cuando se utiliza la combinación de actualizaciones con un tratamiento adecuado de los objetos nuevos, más del 99 % de las actualizaciones de contadores se eliminan para las pruebas comparativas típicas de Java.

Curiosamente, la combinación de actualizaciones también elimina la necesidad de emplear operaciones atómicas durante las actualizaciones de punteros en una configuración simultánea, lo que resuelve los problemas de recuento de referencias en una configuración simultánea. Por lo tanto, la combinación de actualizaciones resuelve el tercer problema del recuento de referencias ingenuo (es decir, una sobrecarga costosa en un entorno concurrente). Levanoni y Petrank presentaron un algoritmo mejorado que puede ejecutarse simultáneamente con aplicaciones de subprocesos múltiples que emplean solo una sincronización fina.

El método de recuento de referencias ulteriores de Blackburn y McKinley en 2003 combina el recuento de referencias diferidas con una guardería de copias, observando que la mayoría de las mutaciones de puntero ocurren en objetos jóvenes. Este algoritmo logra un rendimiento comparable con los recopiladores de copias generacionales más rápidos con los tiempos de pausa limitados bajos del conteo de referencia.

Tratar con ciclos de referencia

Quizás la forma más obvia de manejar los ciclos de referencia es diseñar el sistema para evitar crearlos. Un sistema puede prohibir explícitamente los ciclos de referencia; los sistemas de archivos con enlaces duros a menudo hacen esto. Uso juicioso de "débil" las referencias (no contadas) también pueden ayudar a evitar ciclos de retención; el marco Cocoa, por ejemplo, recomienda usar "strong" referencias para relaciones padre-hijo y "débil" referencias para las relaciones entre padres e hijos.

Los sistemas también pueden estar diseñados para tolerar o corregir los ciclos que crean de alguna manera. Los desarrolladores pueden diseñar código para "derribar" las referencias en una estructura de datos cuando ya no se necesitan, aunque esto tiene el costo de exigirles que realicen un seguimiento manual de la vida útil de esa estructura de datos. Esta técnica se puede automatizar creando un "propietario" objeto que hace el derribo cuando es destruido; por ejemplo, el destructor de un objeto Graph podría eliminar los bordes de sus GraphNodes, rompiendo los ciclos de referencia en el gráfico. Los ciclos pueden incluso ignorarse en sistemas con vidas cortas y una pequeña cantidad de basura cíclica, particularmente cuando el sistema se desarrolló utilizando una metodología para evitar estructuras de datos cíclicas siempre que sea posible, generalmente a expensas de la eficiencia.

Los informáticos también han descubierto formas de detectar y recopilar ciclos de referencia automáticamente, sin necesidad de cambios en el diseño de la estructura de datos. Una solución simple es usar periódicamente un recolector de basura de rastreo para recuperar ciclos; dado que los ciclos normalmente constituyen una cantidad relativamente pequeña de espacio reclamado, el recolector se puede ejecutar con mucha menos frecuencia que con un recolector de elementos no utilizados de rastreo ordinario.

Bacon describe un algoritmo de recopilación cíclica para el recuento de referencias con similitudes con los recopiladores de rastreo, incluidos los mismos límites de tiempo teóricos. Se basa en la observación de que un ciclo solo se puede aislar cuando un recuento de referencia se reduce a un valor distinto de cero. Todos los objetos en los que esto ocurre se colocan en una lista de raíces y luego, periódicamente, el programa busca ciclos a través de los objetos accesibles desde las raíces. Sabe que ha encontrado un ciclo que se puede recopilar cuando la disminución de todos los recuentos de referencia en un ciclo de referencias los lleva a cero. Una versión mejorada de este algoritmo por Paz et al. puede ejecutarse simultáneamente con otras operaciones y mejorar su eficiencia mediante el uso del método de fusión de actualizaciones de Levanoni y Petrank.

Formas variantes

Aunque es posible aumentar los recuentos de referencias simples de varias maneras, a menudo se puede encontrar una mejor solución realizando el recuento de referencias de una manera fundamentalmente diferente. Aquí describimos algunas de las variantes del conteo de referencias y sus ventajas e inconvenientes.

Recuento ponderado de referencias

En el conteo ponderado de referencias, a cada referencia se le asigna un peso, y cada objeto rastrea no el número de referencias que se refieren a él, sino el peso total de las referencias que se refieren a él. La referencia inicial a un objeto recién creado tiene un gran peso, como 216. Cada vez que se copia esta referencia, la mitad del peso va a la nueva referencia y la mitad del peso se queda con la referencia anterior. Dado que el peso total no cambia, no es necesario actualizar el recuento de referencia del objeto.

Al destruir una referencia, se reduce el peso total según el peso de esa referencia. Cuando el peso total llega a cero, todas las referencias han sido destruidas. Si se intenta copiar una referencia con un peso de 1, la referencia tiene que "obtener más peso" sumando al peso total y luego sumando este nuevo peso a la referencia, y luego dividiéndolo. Una alternativa en esta situación es crear un objeto de referencia de indirección, cuya referencia inicial se crea con un gran peso que luego se puede dividir.

La propiedad de no tener que acceder a un recuento de referencias cuando se copia una referencia es particularmente útil cuando el acceso al recuento de referencias del objeto es costoso, por ejemplo, porque está en otro proceso, en el disco o incluso a través de una red. También puede ayudar a aumentar la simultaneidad al evitar que muchos subprocesos bloqueen un recuento de referencias para aumentarlo. Por lo tanto, el conteo ponderado de referencias es más útil en aplicaciones paralelas, multiproceso, de base de datos o distribuidas.

El principal problema con el recuento de referencia ponderado simple es que destruir una referencia aún requiere acceder al recuento de referencia y, si se destruyen muchas referencias, esto puede causar los mismos cuellos de botella que buscamos evitar. Algunas adaptaciones del conteo de referencia ponderado buscan evitar esto transfiriendo el peso de una referencia moribunda a una referencia activa.

El recuento ponderado de referencias fue ideado de forma independiente por Bevan y Watson & Watson en 1987.

Recuento de referencias indirectas

En el conteo indirecto de referencias, es necesario realizar un seguimiento de la fuente de la referencia. Esto significa que se mantienen dos referencias al objeto: una directa que se usa para invocaciones; y uno indirecto que forma parte de un árbol de difusión, como en el algoritmo de Dijkstra-Scholten, que permite a un recolector de basura identificar objetos muertos. Este enfoque evita que un objeto se descarte prematuramente.

Ejemplos de uso

Recolección de basura

Como algoritmo de recopilación, el conteo de referencias rastrea, para cada objeto, un conteo del número de referencias que tienen otros objetos. Si el recuento de referencias de un objeto llega a cero, el objeto se vuelve inaccesible y se puede destruir.

Cuando se destruye un objeto, todos los objetos a los que ese objeto hace referencia también reducen su número de referencias. Debido a esto, la eliminación de una sola referencia puede conducir potencialmente a la liberación de una gran cantidad de objetos. Una modificación común permite que el conteo de referencias se haga incremental: en lugar de destruir un objeto tan pronto como su conteo de referencias llega a cero, se agrega a una lista de objetos sin referencia y periódicamente (o según sea necesario) uno o más elementos de esta lista se eliminan. destruido.

Los recuentos de referencia simples requieren actualizaciones frecuentes. Cada vez que se destruye o sobrescribe una referencia, el número de referencias del objeto al que hace referencia se reduce, y cada vez que se crea o copia uno, el número de referencias del objeto al que hace referencia se incrementa.

El conteo de referencias también se usa en sistemas de archivos y sistemas distribuidos, donde la recolección de basura de seguimiento no incremental completa consume demasiado tiempo debido al tamaño del gráfico de objetos y la velocidad de acceso lenta.

Modelo de objetos componentes

El modelo de objetos componentes (COM) de Microsoft y WinRT hacen un uso generalizado del recuento de referencias. De hecho, dos de los tres métodos que todos los objetos COM deben proporcionar (en la interfaz IUnknown) incrementan o reducen el número de referencias. Gran parte de Windows Shell y muchas aplicaciones de Windows (incluidos MS Internet Explorer, MS Office e innumerables productos de terceros) se basan en COM, lo que demuestra la viabilidad del recuento de referencias en sistemas a gran escala.

Una motivación principal para contar referencias en COM es habilitar la interoperabilidad entre diferentes lenguajes de programación y sistemas de tiempo de ejecución. Un cliente solo necesita saber cómo invocar métodos de objetos para administrar el ciclo de vida de los objetos; por lo tanto, el cliente se abstrae por completo de cualquier asignador de memoria que utilice la implementación del objeto COM. Como ejemplo típico, un programa de Visual Basic que usa un objeto COM es independiente de si ese objeto fue asignado (y luego debe ser desasignado) por un asignador de C++ u otro componente de Visual Basic.

C++

C++ no realiza el conteo de referencias de manera predeterminada, cumpliendo con su filosofía de no agregar funcionalidades que puedan incurrir en gastos generales donde el usuario no lo haya solicitado explícitamente. Se puede acceder a los objetos que se comparten pero que no se poseen a través de una referencia, un puntero sin procesar o un iterador (una generalización conceptual de los punteros).

Sin embargo, de la misma manera, C++ proporciona formas nativas para que los usuarios opten por dicha funcionalidad: C++11 proporciona punteros inteligentes de recuento de referencia, a través de la clase std::shared_ptr, lo que permite la gestión automática de memoria compartida de asignados dinámicamente objetos. Los programadores pueden usar esto junto con punteros débiles (a través de std::weak_ptr) para romper las dependencias cíclicas. Los objetos que se asignan dinámicamente pero que no están destinados a ser compartidos pueden tener su vida útil administrada automáticamente mediante un std::unique_ptr.

Además, la semántica de movimiento de C++11 reduce aún más la necesidad de modificar los recuentos de referencias al eliminar la copia profunda que normalmente se usa cuando una función devuelve un objeto, ya que permite una copia simple de el puntero de dicho objeto.

Cacao (Objetivo-C)

Los marcos Cocoa y Cocoa Touch de Apple (y los marcos relacionados, como Core Foundation) utilizan el recuento manual de referencias, de manera muy similar a COM. Tradicionalmente, esto lo lograba el programador enviando manualmente mensajes retain y release a los objetos, pero se agregó el Recuento automático de referencias, una función del compilador Clang que inserta automáticamente estos mensajes según sea necesario. iOS 5 y Mac OS X 10.7. Mac OS X 10.5 introdujo un recolector de elementos no utilizados de seguimiento como alternativa al recuento de referencias, pero quedó obsoleto en OS X 10.8 y se eliminó de la biblioteca de tiempo de ejecución de Objective-C en macOS Sierra. iOS nunca ha admitido un recolector de elementos no utilizados de seguimiento.

Delfos

Delphi no es principalmente un lenguaje de recolección de elementos no utilizados, en el sentido de que los tipos definidos por el usuario aún deben asignarse y desasignarse manualmente; sin embargo, proporciona una recopilación automática mediante el recuento de referencias para algunos tipos integrados, como cadenas, matrices dinámicas, e interfaces, para facilitar el uso y simplificar la funcionalidad genérica de la base de datos. Depende del programador decidir si usar los tipos integrados; Los programadores de Delphi tienen acceso completo a la gestión de memoria de bajo nivel como en C/C++. Por lo tanto, todo el costo potencial del conteo de referencias de Delphi puede, si se desea, eludirse fácilmente.

Algunas de las razones por las que el conteo de referencias puede haber sido preferido a otras formas de recolección de basura en Delphi incluyen:

  • Los beneficios generales del recuento de referencias, como la recopilación rápida.
  • Los ciclos no pueden ocurrir o no ocurrir en la práctica porque ninguno de los tipos incorporados recolectados por la basura son recursivos. (utilizando interfaces uno podría crear tal escenario, pero eso no es uso común)
  • El tamaño superior del código requerido para el recuento de referencia es muy pequeño (en x86 nativos, típicamente un único LOCK INC, LOCK DEC o LOCK XADD instrucción, que asegura la atomicidad en cualquier entorno), y no se necesita ningún hilo separado de control para la recogida como sería necesario para un recolector de basura rastreador.
  • Muchas instancias del tipo de basura más utilizado, la cadena, tienen una vida corta, ya que son valores típicamente intermedios en la manipulación de cuerdas. Un montón de uso de cadena local podría ser optimizado, pero el compilador actualmente no lo hace.
  • El recuento de referencia de una cadena se verifica antes de mutar una cadena. Esto permite que el recuento de referencia 1 cadenas sean mutadas directamente mientras que las cadenas de recuento de referencia más altas se copian antes de la mutación. Esto permite conservar el comportamiento general de cuerdas pascales de estilo antiguo, eliminando el costo de copiar la cadena en cada asignación.
  • Debido a que la recolección de basura sólo se hace en tipos incorporados, la cuenta de referencia puede integrarse eficientemente en las rutinas de la biblioteca utilizadas para manipular cada tipo de datos, manteniendo el sobrecabezamiento necesario para la actualización de referencia cuenta bajo. Además, mucha de la biblioteca de tiempo de funcionamiento está en ensamblador optimizado a mano.
  • El tipo de cadena puede ser lanzado a un puntero a char, y las operaciones de alto rendimiento se pueden realizar de esa manera. Esto es importante ya que tanto Delphi como FPC implementan su RTL en Pascal. Varios otros tipos automatizados tienen tales opciones de fundición.

OBjeto

El marco de programación orientado a objetos de GObject implementa el recuento de referencias en sus tipos base, incluidas las referencias débiles. El incremento y decremento de referencias utiliza operaciones atómicas para la seguridad de subprocesos. Una parte significativa del trabajo de escribir enlaces a GObject desde lenguajes de alto nivel radica en adaptar el conteo de referencias de GObject para que funcione con el propio sistema de administración de memoria del lenguaje.

El lenguaje de programación Vala utiliza el conteo de referencias de GObject como su principal sistema de recolección de elementos no utilizados, junto con el manejo de cadenas con muchas copias.

Perl

Perl también usa el conteo de referencias, sin ningún manejo especial de referencias circulares, aunque (como en Cocoa y C++ arriba), Perl admite referencias débiles, lo que permite a los programadores evitar la creación de un ciclo.

PHP

PHP utiliza un mecanismo de conteo de referencias para su gestión de variables internas. Desde PHP 5.3, implementa el algoritmo del artículo mencionado anteriormente de Bacon. PHP le permite activar y desactivar la colección de ciclos con funciones a nivel de usuario. También le permite forzar manualmente la ejecución del mecanismo de purga.

Pitón

Python también usa el conteo de referencias y también ofrece detección de ciclos (y puede recuperarlos).

Óxido

Rust usa tiempos de vida declarados en el código para liberar memoria. Rust tiene una estructura Rc y Arc.

El tipo Rc<T> proporciona propiedad compartida de un valor de tipo T, asignado en el montón.

uso std::rc::Rc;struct Gato {} color: String,}f principal() {} Deja gato = Gato {} color: "negro".to_string() }; Deja gato = Rc::nuevo()gato);}

Ardilla

Squirrel usa conteo de referencia con detección de ciclo. Este diminuto lenguaje es relativamente desconocido fuera de la industria de los videojuegos; sin embargo, es un ejemplo concreto de cómo el conteo de referencias puede ser práctico y eficiente (especialmente en entornos de tiempo real).

Tcl

Tcl 8 utiliza el conteo de referencias para la gestión de memoria de valores (estructuras Tcl Obj). Dado que los valores de Tcl's son inmutables, los ciclos de referencia son imposibles de formar y no se necesita un esquema de detección de ciclos. Las operaciones que reemplazarían un valor con una copia modificada generalmente se optimizan para modificar el original cuando su recuento de referencia indica que no se comparte. Las referencias se contabilizan a nivel de estructura de datos, por lo que no surgen los problemas de actualizaciones muy frecuentes comentados anteriormente.

Xojo

Xojo también usa el conteo de referencias, sin ningún manejo especial de referencias circulares, aunque (como en Cocoa y C++ arriba), Xojo admite referencias débiles, lo que permite a los programadores evitar crear un ciclo.

Sistemas de archivos

Muchos sistemas de archivos mantienen recuentos de referencias a cualquier bloque o archivo en particular, por ejemplo, el recuento de enlaces de inodos en los sistemas de archivos de estilo Unix, que generalmente se conocen como enlaces duros. Cuando el recuento llega a cero, el archivo se puede desasignar de forma segura. Si bien aún se pueden hacer referencias desde directorios, algunos Unix solo permiten referencias desde procesos en vivo, y puede haber archivos que existan fuera de la jerarquía del sistema de archivos.

Contenido relacionado

XSL (desambiguación)

Función recursiva general

Infraestructura de lenguaje común

Más resultados...
Tamaño del texto:
Copiar