Référence faible - Weak reference
En programmation informatique , une référence faible est une référence qui ne protège pas l' objet référencé de la collecte par un ramasse-miettes , contrairement à une référence forte. Un objet référencé uniquement par des références faibles - c'est-à-dire « chaque chaîne de références qui atteint l'objet comprend au moins une référence faible en tant que lien » - est considéré comme faiblement accessible , et peut être traité comme inaccessible et peut donc être collecté à tout moment. Certains langages ramassés comportent ou prennent en charge divers niveaux de références faibles, tels que C# , Java , Lisp , OCaml , Perl , Python et PHP depuis la version 7.4.
Les usages
Les références faibles ont un certain nombre de cas d'utilisation courants. Lors de l'utilisation du garbage collection de comptage de références , les références faibles peuvent rompre les cycles de référence , en utilisant une référence faible pour un lien dans le cycle. Lorsqu'on dispose d'un tableau associatif (mapping, hash map) dont les clés sont des (références à) des objets, par exemple pour contenir des données auxiliaires sur des objets, l'utilisation de références faibles pour les clés évite de garder les objets vivants du seul fait de leur utilisation comme clé. Lorsqu'on a un objet où d'autres objets sont enregistrés, comme dans le modèle d'observateur (en particulier dans la gestion d'événements ), si une référence forte est conservée, les objets doivent être explicitement désenregistrés, sinon une fuite de mémoire se produit (le problème de l'écouteur écoulé ), tandis que une référence faible supprime la nécessité de se désinscrire. Lors de la conservation de données mises en cache qui peuvent être recréées si nécessaire, des références faibles permettent de récupérer le cache, produisant ainsi de la mémoire jetable. Ce dernier cas (un cache) est distinct des autres, car il est préférable que les objets ne soient ramassés que si nécessaire, et il y a donc un besoin de distinctions plus fines au sein des références faibles, ici une forme plus forte d'une référence faible. Dans de nombreux cas, il n'est pas nécessaire d'utiliser directement les références faibles, mais simplement d'utiliser un tableau faible ou un autre conteneur dont les clés ou les valeurs sont des références faibles.
Collecte des ordures
La récupération de place est utilisée pour nettoyer les objets inutilisés et ainsi réduire le potentiel de fuites de mémoire et de corruption de données. Il existe deux principaux types de récupération de place : le traçage et le comptage de références . Les schémas de comptage de références enregistrent le nombre de références à un objet donné et collectent l'objet lorsque le nombre de références devient zéro. Le comptage de références ne peut pas collecter de références cycliques (ou circulaires) car un seul objet peut être collecté à la fois. Des groupes d'objets se référençant mutuellement qui ne sont pas directement référencés par d'autres objets et sont inaccessibles peuvent ainsi devenir résidents permanents ; si une application génère continuellement de tels groupes d'objets inaccessibles, cela aura pour effet une fuite de mémoire . Les références faibles (références qui ne sont pas comptées dans le comptage des références) peuvent être utilisées pour résoudre le problème des références circulaires si les cycles de référence sont évités en utilisant des références faibles pour certaines des références au sein du groupe.
Un cas très courant de telles distinctions de références fortes et faibles est dans les structures arborescentes, telles que le modèle objet de document (DOM), où les références parent-enfant sont fortes, mais les références enfant-parent sont faibles. Par exemple, le framework Cocoa d'Apple recommande cette approche. En effet, même lorsque le graphe d'objets n'est pas un arbre, une structure arborescente peut souvent être imposée par la notion de propriété d'objet, où les relations de propriété sont fortes et forment un arbre, et les relations de non-propriété sont faibles et ne sont pas nécessaires pour former l'arbre. – cette approche est courante en C++ (pré-C++11), utilisant des pointeurs bruts comme références faibles. Cette approche, cependant, a l'inconvénient de ne pas permettre de détecter quand une branche parent a été supprimée et supprimée. Depuis le standard C++11 , une solution a été ajoutée en utilisant des ptr partagés et des ptr faibles , hérités de la bibliothèque Boost .
Les références faibles sont également utilisées pour minimiser le nombre d'objets inutiles en mémoire en permettant au programme d'indiquer quels objets sont d'importance mineure en ne les référençant que faiblement.
Variantes
Certaines langues ont plusieurs niveaux de force de référence faible. Par exemple, Java a, par ordre décroissant de force, des références soft , faible et fantôme , définies dans le package java.lang.ref . A chaque type de référence est associée une notion d'accessibilité. Le ramasse-miettes (GC) utilise le type d'accessibilité d'un objet pour déterminer quand libérer l'objet. Le GC peut libérer un objet accessible en douceur, mais le GC peut décider de ne pas le faire s'il pense que la JVM peut économiser de la mémoire (par exemple, la JVM a beaucoup d'espace de tas inutilisé). Le GC libérera un objet faiblement accessible dès que le GC remarquera l'objet. Contrairement aux autres types de référence, une référence fantôme ne peut pas être suivie. D'un autre côté, les références fantômes fournissent un mécanisme pour notifier le programme lorsqu'un objet a été libéré (la notification est implémentée en utilisant ReferenceQueues).
En C#, les références faibles sont distinguées selon qu'elles suivent ou non la résurrection des objets . Cette distinction ne se produit pas pour les références fortes, car les objets ne sont pas finalisés s'ils ont des références fortes à eux. Par défaut, en C#, les références faibles ne suivent pas la résurrection, ce qui signifie qu'une référence faible n'est pas mise à jour si un objet est ressuscité ; celles-ci sont appelées références faibles courtes , et les références faibles qui suivent la résurrection sont appelées références faibles longues .
Certains langages non récupérables, tels que C++ , fournissent une fonctionnalité de référence faible/forte dans le cadre de la prise en charge des bibliothèques de récupération de place. La bibliothèque Boost C++ fournit des références fortes et faibles. C'est une erreur d'utiliser des pointeurs C++ normaux comme équivalents faibles des pointeurs intelligents, car une telle utilisation supprime la possibilité de détecter lorsque le nombre de références fortes est passé à 0 et que l'objet a été supprimé. Pire encore, il ne permet pas de détecter si une autre référence forte suit déjà un pointeur simple donné. Cela introduit la possibilité d'avoir deux (ou plus) pointeurs intelligents suivant le même pointeur simple (ce qui provoque une corruption dès que le nombre de références de l'un de ces pointeurs intelligents atteint 0 et que l'objet est supprimé).
Exemples
Des références faibles peuvent être utiles pour conserver une liste des variables actuelles référencées dans l'application. Cette liste doit avoir des liens faibles vers les objets. Sinon, une fois les objets ajoutés à la liste, ils seront référencés par celle-ci et persisteront pendant toute la durée du programme.
Java
Java 1.2 en 1998 a introduit deux types de références faibles, l'une connue sous le nom de « référence logicielle » (destiné à être utilisé pour maintenir les caches en mémoire gérés par GC, mais qui ne fonctionne pas très bien en pratique sur certaines plates-formes avec un tas dynamique comme Android) et l'autre simplement comme « référence faible ». Il a également ajouté un mécanisme expérimental connexe appelé « références fantômes » comme alternative au mécanisme finalize () dangereux et inefficace.
Si une référence faible est créée, puis qu'elle get()est utilisée ailleurs dans le code pour obtenir l'objet réel, la référence faible n'est pas assez forte pour empêcher le ramasse-miettes, il se peut donc (s'il n'y a pas de références fortes à l'objet) que get()commence soudainement à retourner null.
import java.lang.ref.WeakReference;
public class ReferenceTest {
public static void main(String[] args) throws InterruptedException {
WeakReference r = new WeakReference("I'm here");
StrongReference sr = new StrongReference("I'm here");
System.out.println("Before gc: r=" + r.get() + ", static=" + sr.get());
System.gc();
Thread.sleep(100);
// Only r.get() becomes null.
System.out.println("After gc: r=" + r.get() + ", static=" + sr.get());
}
}
Une autre utilisation des références faibles est l'écriture d'un cache . A l'aide, par exemple, d'une hash map faible , on peut stocker dans le cache les différents objets référencés via une référence faible. Lorsque le ramasse-miettes s'exécute - lorsque par exemple l'utilisation de la mémoire de l'application devient suffisamment élevée - les objets mis en cache qui ne sont plus directement référencés par d'autres objets sont supprimés du cache.
Petite conversation
|a s1 s2|
s1 := 'hello' copy. "that's a strong reference"
s2 := 'world' copy. "that's a strong reference"
a := WeakArray with:s1 with:s2.
a printOn: Transcript.
ObjectMemory collectGarbage.
a printOn: Transcript. "both elements still there"
s1 := nil. "strong reference goes away"
ObjectMemory collectGarbage.
a printOn: Transcript. "first element gone"
s2 := nil. "strong reference goes away"
ObjectMemory collectGarbage.
a printOn: Transcript. "second element gone"
Lua
weak_table = setmetatable({}, {__mode="v"})
weak_table.item = {}
print(weak_table.item)
collectgarbage()
print(weak_table.item)
Objectif-C 2.0
Dans Objective-C 2.0, non seulement le ramasse-miettes, mais aussi le comptage automatique des références seront affectés par des références faibles. Toutes les variables et propriétés de l'exemple suivant sont faibles.
@interface WeakRef : NSObject
{
__weak NSString *str1;
__unsafe_unretained NSString *str2;
}
@property (nonatomic, weak) NSString *str3;
@property (nonatomic, unsafe_unretained) NSString *str4;
@end
La différence entre weak( __weak) et unsafe_unretained( __unsafe_unretained) est que lorsque l'objet vers lequel la variable pointait est désalloué, que la valeur de la variable soit modifiée ou non. weakceux seront mis à jour nilet unsafe_unretainedcelui restera inchangé, en tant que pointeur pendant . Les weakréférences sont ajoutées à Objective-C depuis Mac OS X 10.7 "Lion" et iOS 5 , ainsi que Xcode 4.1 (4.2 pour iOS), et uniquement lors de l'utilisation d'ARC. Les anciennes versions de Mac OS X, iOS et GNUstep ne prennent en charge que les unsafe_unretainedréférences faibles.
Vala
class Node {
public weak Node prev; // a weak reference is used to avoid circular references between nodes of a doubly-linked list
public Node next;
}
Python
>>> 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'
Voir également
Les références
- Goldshtein, Sacha ; Zurbalev, Dima ; Flatow, Ido (2012). Performances Pro .NET : optimisez vos applications C# . Apress. ISBN 978-1-4302-4458-5.
Liens externes
C++
-
Bibliothèque standard C++11 :
std::weak_ptrréférence -
Boost 1.59 (bibliothèque C++) :
boost::weak_ptrréférence
Java
- Article de développeur Java : « Objets de référence et récupération de place »
- Nicholas, Ethan (4 mai 2006). "Comprendre les références faibles" . java.net . Archivé de l'original le 2011-03-03 . Consulté le 1er octobre 2010 .
- RCache - Bibliothèque Java pour un cache basé sur des références faibles/soft
- Théorie et pratique Java : colmater les fuites de mémoire avec des références faibles
PHP
Python
- https://docs.python.org/3/library/weakref.html
- Fred L. Drake, Jr., PEP 205 : références faibles , proposition d'amélioration de Python, janvier 2001.