Vés al contingut

Referència feble

De la Viquipèdia, l'enciclopèdia lliure

En programació informàtica, una referència feble és una referència que no protegeix l'objecte referenciat de la recollida per part d'un col·lector de memòria brossa, a diferència d'una referència forta. Un objecte referit només per referències febles, és a dir, "cada cadena de referències que arriba a l'objecte inclou almenys una referència feble com a enllaç" - es considera que és feblement accessible i es pot tractar com a inabastable i, per tant, es pot recollir en qualsevol moment. Alguns llenguatges de recollida de memòria brossa presenten o admeten diversos nivells de referències febles, com ara C#, Java, Lisp, OCaml, Perl, Python i PHP des de la versió 7.4.[1]

Usos[modifica]

Les referències febles tenen diversos usos comuns. Quan s'utilitza la recollida de memòria brossa de recompte de referències, les referències febles poden trencar els cicles de referència utilitzant una referència feble per a un enllaç del cicle. Quan es disposa d'una matriu associativa (mapping, hash map) les claus de la qual són (referències a) objectes, per exemple per contenir dades auxiliars sobre objectes, utilitzar referències febles per a les claus evita mantenir els objectes vius només pel seu ús com a claus. Quan es té un objecte on hi ha altres objectes registrats, com en el patró d'observador (especialment en el maneig d'esdeveniments), si es manté una referència forta, els objectes s'han de no registrar explícitament, en cas contrari es produeix una fuga de memòria (el problema de l'escolta caducada), mentre una referència feble elimina la necessitat de cancel·lar el registre. Quan es mantenen dades a la memòria cau que es poden recrear si cal, les referències febles permeten recuperar la memòria cau, produint eficaçment memòria descartable. Aquest darrer cas (una memòria cau) és diferent d'altres, ja que és preferible que els objectes només siguin memòria brossa si cal, i per tant cal fer distincions més fines dins de les referències febles, aquí una forma més forta de referència feble. En molts casos, no cal fer servir directament les referències febles, sinó simplement utilitzar una matriu feble o un altre contenidor les claus o valors del qual són referències febles.

Recollida de memòria brossa[modifica]

La recollida de memòria brossa s'utilitza per netejar objectes no utilitzats i reduir així el potencial de fuites de memòria i de corrupció de dades. Hi ha dos tipus principals de recollida de memòria brossa: el rastreig i el recompte de referències. Els esquemes de recompte de referències registren el nombre de referències a un objecte determinat i recullen l'objecte quan el recompte de referències es converteix en zero. El recompte de referències no pot recopilar referències cícliques (o circulars) perquè només es pot recollir un objecte alhora. Els grups d'objectes que es refereixen mútuament als quals altres objectes no fan referència directament i que no són accessibles poden, per tant, convertir-se en residents permanents; si una aplicació genera contínuament aquests grups inabastables d'objectes inabastables, això tindrà l'efecte d'una pèrdua de memòria. Les referències febles (referències que no es compten en el recompte de referències) es poden utilitzar per resoldre el problema de les referències circulars si s'eviten els cicles de referència utilitzant referències febles per a algunes de les referències del grup.

Un cas molt comú d'aquestes distincions de referència fortes i febles és a les estructures d'arbre, com el Document Object Model (DOM), on les referències de pare a fill són fortes, però les referències de fill a pare són febles. Per exemple, el marc de cacau d'Apple recomana aquest enfocament.[2] De fet, fins i tot quan el gràfic d'objectes no és un arbre, una estructura d'arbre sovint es pot imposar per la noció de propietat de l'objecte, on les relacions de propietat són fortes i formen un arbre, i les relacions de no propietat són febles i no són necessàries per formar l'arbre. – aquest enfocament és comú en C++ (pre-C++11), utilitzant punters en brut com a referències febles. Aquest enfocament, però, té l'inconvenient de no permetre la possibilitat de detectar quan s'ha eliminat i suprimit una branca principal. Des de l'estàndard C++11, es va afegir una solució utilitzant shared_ptr i weak_ptr, heretats de la biblioteca Boost.

Les referències febles també s'utilitzen per minimitzar el nombre d'objectes innecessaris a la memòria permetent que el programa indiqui quins objectes són de menor importància fent-hi una referència feble.

Variacions[modifica]

Alguns llenguatges tenen diversos nivells de força de referència feble. Per exemple, Java té, per ordre decreixent de força, referències suaus, febles i fantasma, definides al paquet java.lang.ref.[3] Cada tipus de referència té associada una noció d'accessibilitat. El col·lector de memòria brossa (GC) utilitza el tipus d'accessibilitat d'un objecte per determinar quan alliberar l'objecte. És segur que el GC alliberi un objecte al qual es pot accedir suaument, però el GC pot decidir no fer-ho si creu que la JVM pot estalviar la memòria (p. ex., la JVM té molt espai de pila no utilitzat). El GC alliberarà un objecte feblement accessible tan bon punt el GC s'adoni de l'objecte. A diferència dels altres tipus de referència, no es pot seguir una referència fantasma. D'altra banda, les referències fantasma proporcionen un mecanisme per notificar al programa quan s'ha alliberat un objecte (la notificació s'implementa mitjançant ReferenceQueues).

En C#, les referències febles es distingeixen per si fan un seguiment de la resurrecció d'objectes o no. Aquesta distinció no es produeix per a referències fortes, ja que els objectes no es finalitzen si tenen referències fortes a ells. Per defecte, en C# la referència feble no fa un seguiment de la resurrecció, és a dir, una referència feble no s'actualitza si un objecte ressuscita; aquestes s'anomenen referències febles curtes, i les referències febles que rastregen la resurrecció s'anomenen referències febles llargues.[4]

Alguns llenguatges que no es recullen a la memòria brossa, com ara C++, proporcionen una funcionalitat de referència feble/forta com a part del suport de biblioteques de recollida de memòria brossa. La biblioteca Boost C++ proporciona referències fortes i febles. És un error utilitzar punters C++ normals com a homòlegs febles dels punters intel·ligents perquè aquest ús elimina la capacitat de detectar quan el recompte de referències forts ha passat a 0 i l'objecte s'ha suprimit. Pitjor encara, no permet la detecció de si una altra referència forta ja està fent el seguiment d'un punter senzill determinat. Això introdueix la possibilitat de tenir dos (o més) punters intel·ligents que segueixen el mateix punter senzill (la qual cosa provoca corrupció tan bon punt un d'aquests punters intel·ligents arriba a 0 i l'objecte s'elimina).[5]

Exemples[modifica]

Les referències febles poden ser útils quan es manté una llista de les variables actuals a les quals es fa referència a l'aplicació. Aquesta llista ha de tenir enllaços febles als objectes. En cas contrari, un cop s'afegeixin objectes a la llista, se'ls farà referència i es mantindran durant la durada del programa.

Python[modifica]

>>> import weakref
>>> import gc
>>> class Egg:
...     def spam(self):
...         print("I'm alive!")
...
>>> obj = Egg()
>>> weak_obj = weakref.ref(obj)
>>> weak_obj().spam()
I'm alive!
>>> obj = "Something else"
>>> gc.collect()
35
>>> weak_obj().spam()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'spam'

Referències[modifica]

  1. «PHP: WeakReference - Manual» (en anglès).
  2. «Practical Memory Management» (en anglès). developer.apple.com.
  3. Nicholas, Ethan. «Understanding Weak References» (en anglès). java.net, May 4, 2006. Arxivat de l'original el 2011-03-03. [Consulta: October 1, 2010].
  4. Goldshtein, Zurbalev i Flatow, 2012, p. 131.
  5. gewarren. «Weak References - .NET» (en anglès americà), 15-09-2021. [Consulta: 27 desembre 2023].