En programación informática , una referencia débil es una referencia que no protege al objeto referenciado de la recolección por parte del recolector de basura , a diferencia de una referencia fuerte. Un objeto referenciado solo por referencias débiles —es decir, "cada cadena de referencias que llega al objeto incluye al menos una referencia débil como enlace"— se considera débilmente alcanzable y puede tratarse como inalcanzable , por lo que puede ser recolectado en cualquier momento. Algunos lenguajes con recolección de basura presentan o admiten varios niveles de referencias débiles, como C# , Lua , [ 1 ] Java , Lisp , OCaml , MATLAB , [ 2 ] Perl , Python , [ 3 ] Racket y PHP desde la versión 7.4. [ 4 ]
Usos
Las referencias débiles tienen varios usos comunes. Al usar la recolección de basura por conteo de referencias , las referencias débiles pueden romper ciclos de referencia , al usar una referencia débil para un enlace en el ciclo. Cuando se tiene un arreglo asociativo (mapping, hash map) cuyas claves son (referencias a) objetos, por ejemplo para almacenar datos auxiliares sobre objetos, usar referencias débiles para las claves evita que los objetos permanezcan activos solo por su uso como claves. Cuando se tiene un objeto donde se registran otros objetos, como en el patrón observador (particularmente en el manejo de eventos ), si se mantiene una referencia fuerte, los objetos deben ser desregistrados explícitamente, de lo contrario se produce una fuga de memoria (el problema del oyente lapso ), mientras que una referencia débil elimina la necesidad de desregistrar. Cuando se almacenan datos en caché que se pueden recrear si es necesario, las referencias débiles permiten recuperar la caché, produciendo efectivamente memoria descartable. Este último caso (una caché) se distingue de los demás, ya que es preferible que los objetos solo se eliminen mediante el recolector de basura cuando sea necesario. Por lo tanto, se requieren distinciones más precisas dentro de las referencias débiles, en este caso, una forma más robusta de referencia débil. En muchos casos, no es necesario usar referencias débiles directamente, sino simplemente utilizar un array débil u otro contenedor cuyas claves o valores sean referencias débiles.
Recogida de basura
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. Existen 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 lo recolectan cuando el contador de referencias llega a 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 que son inaccesibles, pueden convertirse en residentes permanentes; si una aplicación genera continuamente tales grupos de objetos inaccesibles, esto tendrá el efecto de una fuga de memoria . Las referencias débiles (referencias que no se cuentan en el conteo de referencias) pueden usarse para resolver el problema de las referencias circulares si se evitan los ciclos de referencias al usar referencias débiles para algunas de las referencias dentro del grupo.
Un caso muy común de tales distinciones de referencias fuertes vs. débiles se encuentra en estructuras de árbol, como el Modelo de Objetos del 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. [ 5 ] De hecho, incluso cuando el grafo de objetos no es un árbol, una estructura de árbol a menudo puede ser impuesta por la noción de propiedad de objetos, 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++ (anterior a C++11), usando punteros sin formato como referencias débiles. Sin embargo, este enfoque tiene la desventaja de no permitir la capacidad de detectar cuándo se ha eliminado una rama padre. Desde el estándar C++11 , se agregó una solución usando 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 mediante referencias débiles.
Variaciones
Algunos lenguajes tienen varios niveles de fuerza de referencia débil. Por ejemplo, Java tiene, en orden de fuerza decreciente, referencias suaves , débiles y fantasma , definidas en el paquete java.lang.ref . [ 6 ] Cada tipo de referencia tiene una noción de alcanzabilidad asociada. El recolector de basura (GC) utiliza el tipo de alcanzabilidad de un objeto para determinar cuándo liberarlo. Es seguro para el GC liberar un objeto que es alcanzable suavemente, pero el GC puede decidir no hacerlo si cree que la JVM puede ahorrar memoria (por ejemplo, la JVM tiene mucho espacio de montón sin usar). El GC liberará un objeto alcanzable débilmente tan pronto como lo detecte. 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 mediante ReferenceQueues).
En C#, las referencias débiles se distinguen por si rastrean o no la resurrección de objetos . Esta distinción no se aplica a las referencias fuertes, ya que los objetos no se finalizan si tienen alguna referencia fuerte hacia ellos. Por defecto, en C# las referencias débiles no rastrean la resurrección, lo que significa que una referencia débil no se actualiza si un objeto se resucita; estas se denominan referencias débiles cortas , y las referencias débiles que rastrean la resurrección se denominan referencias débiles largas . [ 7 ]
Algunos lenguajes sin recolección de basura, como C++ , ofrecen funcionalidad de referencias débiles y fuertes como parte de sus bibliotecas de recolección de basura. La biblioteca Boost C++ proporciona referencias fuertes y débiles. Es un error usar punteros C++ normales como contrapartes débiles de punteros inteligentes, ya que esto elimina la capacidad de detectar cuándo el contador de referencias fuertes llega a cero y el objeto se ha eliminado. Peor aún, no permite detectar si otra referencia fuerte ya está rastreando un puntero simple dado. Esto introduce la posibilidad de que dos (o más) punteros inteligentes rastreen el mismo puntero simple (lo que provoca corrupción tan pronto como el contador de referencias de uno de estos punteros inteligentes llega a cero y el objeto se elimina).
Ejemplos
Las referencias débiles pueden ser útiles para mantener una lista de las variables a las que se hace referencia en la aplicación. Esta lista debe contener enlaces débiles a los objetos. De lo contrario, una vez que se añaden objetos a la lista, esta los referenciará y estos persistirán durante toda la ejecución del programa.
C++
C++ tiene una std::weak_ptrclase, una especie de puntero inteligente .
importar std ;using std :: shared_ptr ; using std :: weak_ptr ;shared_ptr < int [] > myInts = std :: make_shared < int [] > ( 5 ); weak_ptr < int [] > weakPtr = myInts ;DO#
C# tiene la System.WeakReferenceclase. [ 8 ] [ 9 ]
using System ; using System.Collections.Generic ;Diccionario < int , WeakReference > () myDict = nuevo ();Java
Java 1.2, en 1998, introdujo [ 10 ] dos tipos de referencias débiles: una conocida como "referencia suave" (diseñada para mantener cachés en memoria gestionadas por el recolector de basura, pero que no funciona muy bien en la práctica en algunas plataformas con montón dinámico como Android [ 11 ] ) y la otra simplemente como "referencia débil". También añadió un mecanismo experimental relacionado, denominado "referencias fantasma", como alternativa al finalize()mecanismo peligroso e ineficiente. [ 12 ]
Si se crea una referencia débil y luego en otra parte del código get()se usa 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 null. [ 13 ]
paquete org.wikipedia.examples ;import java.lang.ref.WeakReference ;public class ReferenceTest { public static void main ( String [] args ) throws InterruptedException { WeakReference r = new WeakReference ( "Estoy aquí" ); String s = "Estoy aquí" ; System . out . printf ( "Antes de gc: r=%s, static=%s%n" , r . get (), s ); System . gc (); // se asume que GC está en ejecución Thread . sleep ( 100 );// Solo r.get() se vuelve nulo. System.out.printf ( " Después de gc: r=%s, static=%s%n" , r.get ( ) , s ); } }Otro uso de las referencias débiles es en la escritura de una caché . Por ejemplo, utilizando un mapa hash débil , se pueden almacenar en la caché los distintos objetos referenciados mediante una referencia débil. Cuando se ejecuta el recolector de basura —por ejemplo, cuando el uso de memoria de la aplicación es suficientemente alto— , aquellos objetos almacenados en caché que ya no son referenciados directamente por otros objetos se eliminan de la caché.
Charla informal
| a s1 s2 |s1 := 'hola' copia . "esa es una referencia fuerte" s2 := 'mundo' copia . "esa es una referencia fuerte" a := WeakArray con: s1 con: 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 se ha ido"s2 := nil . "La referencia fuerte desaparece" ObjectMemory collectGarbage . a printOn: Transcript . "El segundo elemento desaparece"Lua
weak_table = setmetatable ({}, { __mode = "v" }) weak_table . item = {} print ( weak_table . item ) collectgarbage () print ( weak_table . item )Objective-C 2.0
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 las referencias débiles. Todas las variables y propiedades del siguiente ejemplo son referencias débiles.
@interface WeakRef : NSObject { __weak NSString * str1 ; __unsafe_unretained NSString * str2 ; }@property ( nonatomic , weak ) NSString * str3 ; @property ( nonatomic , unsafe_unretained ) NSString * str4 ;@finLa diferencia entre weak( __weak) y unsafe_unretained( __unsafe_unretained) es que cuando el objeto al que apunta la variable se desasigna, independientemente de si el valor de la variable va a cambiar o no, weakse actualizará a nily unsafe_unretainedse dejará sin cambios, como un puntero colgante . Las weakreferencias se añadieron 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_unretainedreferencias como débiles.
PHP
PHP tiene la clase WeakReference . [ 14 ]
$obj = new stdClass (); $weakref = WeakReference :: create ( $obj );var_dump ( $weakref -> get ()); sin configurar ( $obj ); var_dump ( $weakref -> get ());Pitón
Python tiene el módulo weakref . [ 15 ]
import gc import weakref from weakref import ReferenceTypeclase Huevo : def spam ( self ) -> Ninguno : print ( "¡Estoy vivo!" )obj : Egg = Egg () weak_obj : ReferenceType [ Egg ] = weakref.ref ( obj ) weak_obj () . spam () # imprime: ¡ Estoy vivo !obj : str = "Algo más" # gc.collect() devuelve un int print ( f "Número de objetos inalcanzables recopilados: { gc . collect () } " ) # imprime: Número de objetos inalcanzables recopilados: 35 weak_obj () . spam () # Traceback (última llamada más reciente): # Archivo "<stdin>", línea 1, en <module> # AttributeError: el objeto 'NoneType' no tiene el atributo 'spam'Óxido
Rust tiene un std::rc::Weakobjeto.
use std :: rc :: Rc ; use std :: rc :: Weak ;let strong_ptr : Rc < i32 > = Rc :: new ( 5 ); let weak_ptr : Weak < i32 > = Rc :: downgrade ( & strong_ptr );Vala
Vala tiene la palabra clave débil . [ 16 ]
clase Nodo { public weak Nodo anterior ; // Se utiliza una referencia débil para evitar referencias circulares entre nodos de una lista doblemente enlazada public Nodo siguiente ; }Véase también
Referencias
- ↑ Lerusalimschy, Roberto (2003). "17 - Tablas débiles". Programación en Lua (1.ª ed.).
- ↑
- ↑ 8.8. weakref — Referencias débiles , La biblioteca estándar de Python
- ↑ "PHP: WeakReference - Manual" .
- ↑ "Gestión práctica de la memoria" . developer.apple.com .
- ↑ Nicholas, Ethan (4 de mayo de 2006). "Understanding Weak References" . java.net . Archivado del original el 3 de marzo de 2011. Recuperado el 1 de octubre de 2010 .
- ↑ Goldshtein, Zurbalev y Flatow 2012 , pág. 131 .
- ↑ "Referencias débiles - .NET" . learn.microsoft.com . Consultado el 9 de julio de 2025 .
- ↑ "WeakReference Class (System)" . learn.microsoft.com . Consultado el 9 de julio de 2025 .
- ^ "Referencia débil (plataforma Java SE 7)" . docs.oracle.com .
- ↑ "SoftReference - Desarrolladores de Android" . developer.android.com .
- ↑ "PhantomReference (Java Platform SE 7)" . docs.oracle.com .
- ↑ https://web.archive.org/web/20110303225354/http://weblogs.java.net/blog/2006/05/04/understanding-weak-references Ejemplos de Java
- ↑ "PHP: WeakReference - Manual" . www.php.net . Consultado el 9 de julio de 2025 .
- ↑ "weakref — Referencias débiles" . Documentación de Python . Consultado el 9 de julio de 2025 .
- ↑ "4.9. Referencias débiles - Documentación de Vala" . docs.vala.dev . Consultado el 9 de julio de 2025 .
- Goldshtein, Sasha; Zurbalev, Dima; Flatow, Ido (2012). Pro .NET Performance: Optimize Your C# Applications . Apress. ISBN 978-1-4302-4458-5.
Enlaces externos
C++
- Biblioteca estándar de C++11 :
std::weak_ptrreferencia - Boost 1.59 (biblioteca C++) :
boost::weak_ptrreferencia
Java
- Artículo para desarrolladores de Java: 'Objetos de referencia y recolección de basura'
- Nicholas, Ethan (4 de mayo de 2006). "Entendiendo las referencias débiles" . java.net . Archivado del original el 19 de agosto de 2010. Recuperado el 1 de octubre de 2010 .
{{cite web}}: CS1 maint: bot: estado de la URL original desconocido ( enlace ) - RCache: biblioteca Java para caché basada en referencias débiles/suaves.
- Teoría y práctica de Java: Cómo solucionar fugas de memoria con referencias débiles
PHP
- Referencias débiles
Pitón
- weakref — Referencias débiles — Documentación de Python 3
- Fred L. Drake Jr., PEP 205: Referencias débiles , Propuesta de mejora de Python, enero de 2001.
- Tipos de datos
- Gestión de la memoria