En programación informática , una referencia débil es una referencia que no protege al objeto referenciado de la recolección por parte de un recolector de basura , a diferencia de una referencia fuerte. Un objeto referenciado solo por referencias débiles, es decir, "cada cadena de referencias que alcanza el objeto incluye al menos una referencia débil como enlace", se considera débilmente alcanzable y puede tratarse como inalcanzable y, por lo tanto, puede recolectarse en cualquier momento. Algunos lenguajes con recolección de basura presentan o admiten varios niveles de referencias débiles, como C# , Lua , Java , Lisp , OCaml , Perl , Python [1] y PHP desde la versión 7.4. [2]
Las referencias débiles tienen varios usos comunes. Cuando se utiliza la recolección de basura de conteo de referencias , las referencias débiles pueden romper los ciclos de referencia , al usar una referencia débil para un enlace en el ciclo. Cuando uno tiene una matriz asociativa (mapeo, mapa hash) cuyas claves son (referencias a) objetos, por ejemplo para contener datos auxiliares sobre objetos, el uso de referencias débiles para las claves evita mantener los objetos vivos solo por su uso como claves. Cuando uno tiene un objeto donde otros objetos están registrados, como en el patrón de observador (particularmente en el manejo de eventos ), si se mantiene una referencia fuerte, los objetos deben desregistrarse explícitamente, de lo contrario se produce una pérdida de memoria (el problema del oyente caducado ), mientras que una referencia débil elimina la necesidad de desregistrar. Cuando se mantienen datos en caché que se pueden recrear si es necesario, las referencias débiles permiten recuperar el caché, produciendo efectivamente memoria descartable. Este último caso (una caché) es distinto de los demás, ya que es preferible que los objetos solo se recopilen como basura si es necesario y, por lo tanto, existe la necesidad de distinciones más precisas dentro de las referencias débiles, en este caso una forma más fuerte de una referencia débil. En muchos casos, no es necesario utilizar directamente las referencias débiles, sino que simplemente se utiliza una matriz débil u otro contenedor cuyas claves o valores sean referencias débiles.
La recolección de basura se utiliza para limpiar objetos no utilizados y así reducir el potencial de fugas de memoria y corrupción de datos. Hay dos tipos principales de recolección de basura: rastreo y conteo de referencias . Los esquemas de conteo de referencias registran el número de referencias a un objeto dado y recolectan el objeto cuando el conteo de referencias se vuelve cero. El conteo de referencias no puede recolectar referencias cíclicas (o circulares) porque solo se puede recolectar un objeto a la vez. Los grupos de objetos que se referencian mutuamente que no son referenciados directamente por otros objetos y son inalcanzables pueden, por lo tanto, convertirse en residentes permanentes; si una aplicación genera continuamente tales grupos inalcanzables de objetos inalcanzables, esto tendrá el efecto de una fuga de memoria . Las referencias débiles (referencias que no se cuentan en el conteo de referencias) se pueden usar para resolver el problema de las referencias circulares si se evitan los ciclos de referencia mediante el uso de referencias débiles para algunas de las referencias dentro del grupo.
Un caso muy común de tales distinciones entre referencias fuertes y débiles se da en las estructuras de árbol, como el Modelo de objetos de documento (DOM), donde las referencias de padre a hijo son fuertes, pero las referencias de hijo a padre son débiles. Por ejemplo, el marco Cocoa de Apple recomienda este enfoque. [3] De hecho, incluso cuando el gráfico de objetos no es un árbol, a menudo se puede imponer una estructura de árbol mediante la noción de propiedad del objeto, donde las relaciones de propiedad son fuertes y forman un árbol, y las relaciones de no propiedad son débiles y no son necesarias para formar el árbol; este enfoque es común en C++ (pre-C++11), utilizando punteros sin formato como referencias débiles. Este enfoque, sin embargo, tiene la desventaja de no permitir la capacidad de detectar cuándo se ha eliminado y eliminado una rama padre. Desde el estándar C++11 , se agregó una solución mediante el uso de shared_ptr y weak_ptr , heredados de la biblioteca Boost .
Las referencias débiles también se utilizan para minimizar la cantidad de objetos innecesarios en la memoria, permitiendo que el programa indique qué objetos son de menor importancia al hacer referencia a ellos sólo de manera débil. [ cita requerida ]
Algunos lenguajes tienen múltiples niveles de fuerza de referencia débil. Por ejemplo, Java tiene, en orden de fuerza decreciente, referencias suaves , débiles y fantasmas , definidas en el paquete java.lang.ref . [4] Cada tipo de referencia tiene una noción asociada de accesibilidad. El recolector de basura (GC) utiliza el tipo de accesibilidad de un objeto para determinar cuándo liberar el objeto. Es seguro para el GC liberar un objeto que es accesible de manera suave, pero el GC puede decidir no hacerlo si cree que la JVM puede ahorrar la memoria (por ejemplo, la JVM tiene mucho espacio de montón sin usar). El GC liberará un objeto débilmente accesible tan pronto como el GC note el objeto. A diferencia de los otros tipos de referencia, una referencia fantasma no se puede seguir. Por otro lado, las referencias fantasma proporcionan un mecanismo para notificar al programa cuando se ha liberado un objeto (la notificación se implementa utilizando ReferenceQueues).
En C#, las referencias débiles se distinguen según si rastrean la resurrección de objetos o no. Esta distinción no se produce en el caso de las referencias fuertes, ya que los objetos no se finalizan si tienen alguna referencia fuerte a ellos. De forma predeterminada, en C# las referencias débiles no rastrean la resurrección, lo que significa que una referencia débil no se actualiza si se resucita un objeto; estas se denominan referencias débiles cortas y las referencias débiles que rastrean la resurrección se denominan referencias débiles largas . [5]
Algunos lenguajes que no recolectan basura, como C++ , proporcionan una funcionalidad de referencia débil/fuerte como parte de las bibliotecas de recolección de basura de soporte. La biblioteca Boost C++ proporciona referencias fuertes y débiles. Es un error usar punteros C++ regulares como las contrapartes débiles de los punteros inteligentes porque dicho uso elimina la capacidad de detectar cuándo el recuento de referencia fuerte ha llegado a 0 y el objeto ha sido eliminado. Peor aún, no permite detectar si otra referencia fuerte ya está rastreando un puntero simple dado. Esto introduce la posibilidad de tener dos (o más) punteros inteligentes rastreando el mismo puntero simple (lo que causa corrupción tan pronto como el recuento de referencia de uno de estos punteros inteligentes llega a 0 y el objeto se elimina).
Las referencias débiles pueden ser útiles para mantener una lista de las variables actuales a las que se hace referencia en la aplicación. Esta lista debe tener vínculos débiles con los objetos. De lo contrario, una vez que se agreguen objetos a la lista, esta hará referencia a ellos y persistirán durante la duración del programa.
En 1998, Java 1.2 introdujo [6] dos tipos de referencias débiles: una conocida como "referencia blanda" (destinada a ser utilizada para mantener cachés en memoria gestionados por GC, pero que no funciona muy bien en la práctica en algunas plataformas con montón dinámico como Android [7] ) y la otra simplemente como "referencia débil". También agregó un mecanismo experimental relacionado denominado "referencias fantasma" como una alternativa al peligroso e ineficiente mecanismo finalize(). [8]
Si se crea una referencia débil y luego se utiliza en otra parte del código get()
para obtener el objeto real, la referencia débil no es lo suficientemente fuerte como para evitar la recolección de basura, por lo que puede ser (si no hay referencias fuertes al objeto) que get()
de repente comience a devolver nulo. [9]
importar java.lang.ref.WeakReference ; clase pública ReferenceTest { public static void main ( String [] args ) lanza InterruptedException { WeakReference r = new WeakReference ( "Estoy aquí" ); StrongReference sr = new StrongReference ( "Estoy aquí" ); System . out . println ( "Antes de gc: r=" + r . get () + ", static=" + sr . get ()); System . gc (); Thread . sleep ( 100 ); // Solo r.get() se vuelve nulo. System . out . println ( "Después de gc: r=" + r . get () + ", static=" + sr . get ()); } }
Otro uso de las referencias débiles es la escritura de una memoria caché . Utilizando, por ejemplo, un mapa hash débil , se pueden almacenar en la memoria caché los distintos objetos a los que se hace referencia mediante una referencia débil. Cuando se ejecuta el recolector de elementos no utilizados (por ejemplo, cuando el uso de memoria de la aplicación es lo suficientemente alto), aquellos objetos almacenados en caché a los que ya no se hace referencia directamente por otros objetos se eliminan de la memoria caché.
| un s1 s2 |s1 := 'hola' copy . "esa es una referencia fuerte" s2 := 'mundo' copy . "esa es una referencia fuerte" a := WeakArray with: s1 with: s2 . a printOn: Transcript . ObjectMemory collectGarbage . a printOn: Transcript . "ambos elementos siguen ahí"s1 := nil . "la referencia fuerte desaparece" ObjectMemory collectGarbage . a printOn: Transcript . "el primer elemento desaparece"s2 := nil . "la referencia fuerte desaparece" ObjectMemory collectGarbage . a printOn: Transcript . "el segundo elemento desaparece"
tabla_débil = setmetatable ({}, { __mode = "v" }) tabla_débil . elemento = {} print ( tabla_débil . elemento ) collectgarbage () print ( tabla_débil . elemento )
En Objective-C 2.0, no solo la recolección de basura, sino también el conteo automático de referencias se verán afectados por referencias débiles. Todas las variables y propiedades en el siguiente ejemplo son débiles.
@interface WeakRef : NSObject { __NSString débil * str1 ; __NSString inseguro_no retenido * str2 ; } @property ( no atómico , débil ) NSString * str3 ; @property ( no atómico , inseguro_no retenido ) NSString * str4 ; @fin
La diferencia entre weak
( __weak
) y unsafe_unretained
( __unsafe_unretained
) es que cuando se desasigna el objeto al que apunta la variable, se indica si se va a cambiar el valor de la variable o no. weak
Los ones se actualizarán a nily el unsafe_unretained
one se dejará sin cambios, como un puntero colgante . Las weak
referencias se agregaron a Objective-C desde Mac OS X 10.7 "Lion" e iOS 5 , junto con Xcode 4.1 (4.2 para iOS), y solo cuando se usa ARC. Las versiones anteriores de Mac OS X, iOS y GNUstep solo admiten unsafe_unretained
referencias como débiles.
clase Nodo { público débil Nodo prev ; // se utiliza una referencia débil para evitar referencias circulares entre nodos de una lista doblemente enlazada público Nodo next ; }
>>> import weakref >>> import gc >>> class Egg : ... def spam ( self ): ... print ( "¡Estoy vivo!" ) ... >>> obj = Egg () >>> weak_obj = weakref . ref ( obj ) >>> weak_obj () . spam () ¡Estoy vivo! >>> obj = "Algo más" >>> gc . collect () 35 >>> weak_obj () . spam () Traceback (most recent call last): Archivo "<stdin>" , línea 1 , en <módulo> AttributeError : el objeto 'NoneType' no tiene el atributo 'spam'
{{cite web}}
: CS1 maint: bot: estado de URL original desconocido ( enlace )