Java: différence entre une référence forte / douce / faible / fantôme

187

J'ai lu cet article sur le sujet, mais je ne le comprends pas vraiment. Veuillez me donner quelques conseils et des exemples pour décrire les concepts.

Matthias Braun
la source
4
J'ai lu ce document, cela ne m'aide pas à imaginer quelle différence. (peut-être parce que c'est un document à lecture difficile)
14
Si vous lisez cet article et que vous ne comprenez toujours pas, avez-vous des questions spécifiques à ce sujet? Il est difficile de répondre à «veuillez m'expliquer Foo», «voici ce que cela signifie», «je ne comprends pas» sans préciser les parties que vous n'obtenez pas.
yshavit
@LouisWasserman Le lien supérieur n'est plus valide.
Mehraj Malik

Réponses:

144

Java fournit deux types / classes d' objets de référence différents : fort et faible . Les objets de référence faibles peuvent être divisés en objets souples et fantômes .

  • Fort
  • Faible
    • doux
    • fantôme

Allons-y point par point.

Objet de référence fort

StringBuilder builder = new StringBuilder();

Il s'agit du type / classe par défaut de l'objet de référence, s'il n'est pas spécifié différemment: builderest un objet de référence fort. Ce type de référence rend l'objet référencé non éligible pour GC. Autrement dit, chaque fois qu'un objet est référencé par une chaîne d'objets de référence forts , il ne peut pas être récupéré.

Objet de référence faible

WeakReference<StringBuilder> weakBuilder = new WeakReference<StringBuilder>(builder);

Les objets de référence faibles ne sont pas le type / classe d'objet de référence par défaut et pour être utilisés, ils doivent être explicitement spécifiés comme dans l'exemple ci-dessus. Ce type de référence rend l'objet de référence éligible pour GC. Autrement dit, dans le cas où la seule référence accessible pour l' StringBuilderobjet en mémoire est, en fait, la référence faible, alors le GC est autorisé à ramasser l' StringBuilderobjet. Lorsqu'un objet en mémoire est accessible uniquement par des objets de référence faibles, il devient automatiquement éligible pour GC.

Niveaux de faiblesse

Deux niveaux différents de faiblesse peuvent être enrôlés: doux et fantôme .

Un objet de référence souple est fondamentalement un objet de référence faible qui reste un peu plus en mémoire: normalement, il résiste au cycle GC jusqu'à ce qu'aucune mémoire ne soit disponible et qu'il y ait un risque de OutOfMemoryError(dans ce cas, il peut être supprimé).

D'un autre côté, un objet de référence fantôme n'est utile que pour savoir exactement quand un objet a été effectivement supprimé de la mémoire: normalement, ils sont utilisés pour corriger le comportement étrange de revival / résurrection de finalize () , car ils ne renvoient pas l'objet lui-même mais seulement aider à garder une trace de leur présence dans la mémoire .

Les objets de référence faibles sont idéaux pour implémenter des modules de cache. En fait, une sorte d'éviction automatique peut être mise en œuvre en permettant au GC de nettoyer les zones mémoire chaque fois que les objets / valeurs ne sont plus accessibles par une chaîne de références forte. Un exemple est le WeakHashMap conservant des clés faibles.

Paolo Maresca
la source
en ajoutant à la Q: strongRef --> weakRef --> objA. Maintenant, sera objAGC ou non, car il a une référence indirecte de strongRef.
samshers
79

Référence faible:

Une référence faible, en termes simples, est une référence qui n'est pas assez forte pour forcer un objet à rester en mémoire. Les références faibles vous permettent de tirer parti de la capacité du garbage collector à déterminer l'accessibilité pour vous, vous n'avez donc pas à le faire vous-même.

Référence souple:

Une référence souple est exactement comme une référence faible, sauf qu'elle est moins désireuse de jeter l'objet auquel elle se réfère. Un objet qui n'est que faiblement accessible (les références les plus fortes sont WeakReferences) sera ignoré au prochain cycle de garbage collection, mais un objet qui est facilement accessible restera généralement pendant un certain temps.

Référence fantôme:

Une référence fantôme est assez différente de SoftReference ou WeakReference. Son emprise sur son objet est si ténue que vous ne pouvez même pas récupérer l'objet - sa méthode get () renvoie toujours null. La seule utilité d'une telle référence est de garder une trace du moment où elle est mise en file d'attente dans une ReferenceQueue, car à ce stade, vous savez que l'objet vers lequel il pointait est mort.

Ce texte a été extrait de: https://weblogs.java.net/blog/2006/05/04/understanding-weak-references

Punith Raj
la source
1
Bien que tout dans cette réponse semble correct, il me semble également qu'il peut y avoir une erreur sur la page Web liée. Le Javadoc pour le package java.lang.ref et celui pour PhantomReference suggèrent qu'un objet n'est pas récupéré jusqu'à ce qu'il ne soit plus "fantôme accessible", ce qui implique que (contrairement à SoftReference) un PhantomReference doit être retiré de la file d'attente avant que l'objet auquel il se réfère ne puisse être garbage collect ... et sa mise en file d'attente n'indique pas que la mémoire associée a été libérée.
Theodore Murdock
2
Pour mémoire, je préférerais de loin vivre dans un monde où cet article de blog est correct.
Theodore Murdock
1
@TheodoreMurdock Le javadoc est correct. Une référence fantôme n'empêche pas du tout le garbage collection. Une fois qu'un objet est mis en file d'attente, il ne peut pas être enregistré, même par un finaliseur, car les finaliseurs sont déjà exécutés. Il est mort, mais pas encore parti.
Leliel
@Leliel En fait, une référence fantôme empêche en fait le ramassage des ordures après sa mise en file d'attente ... Je m'en suis rendu compte récemment quand un bogue a provoqué la fermeture prématurée d'un thread de nettoyage. L'existence de références fantômes était suffisante pour garantir que chaque objet référencé fantôme était conservé dans mon vidage de tas, indisponible pour la collecte ... si vous ne parvenez pas à traiter la file d'attente ou si vous ne parvenez pas à rendre la référence fantôme éligible pour gc lors du traitement de la file d'attente ( et ne pas effacer () la référence fantôme), alors votre fuite de mémoire inclura à la fois la référence fantôme et l'objet référencé.
Theodore Murdock
"Contrairement aux références souples et faibles, les références fantômes ne sont pas automatiquement effacées par le ramasse-miettes lorsqu'elles sont mises en file d'attente. Un objet qui est accessible via des références fantômes le restera jusqu'à ce que toutes ces références soient effacées ou deviennent elles-mêmes inaccessibles." source: Java8 API Docs PhantomReference
theRiley
25

La simple différence entre SoftReferenceet WeakReferenceest fournie par Android Developer .

La différence entre a SoftReferenceet a WeakReferenceest le moment auquel la décision est prise d'effacer et de mettre la référence en file d'attente:

  • A SoftReferencedoit être effacé et mis en file d'attente le plus tard possible, c'est-à-dire au cas où la machine virtuelle risque de manquer de mémoire.

  • A WeakReferencepeut être effacé et mis en file d'attente dès que l'on sait qu'il est faiblement référencé.

Muhammad Nabeel Arif
la source
18

Cet article peut être très utile pour comprendre les références fortes, douces, faibles et fantômes.


Pour vous donner un résumé,

Si vous avez une référence forte à un objet, alors l'objet ne peut jamais être collecté / récupéré par GC (Garbage Collector).

Si vous n'avez que des références faibles à un objet (sans références fortes), alors l'objet sera récupéré par GC au tout prochain cycle GC.

Si vous avez seulement des références logicielles à un objet (sans références fortes), l'objet ne sera récupéré par GC que lorsque la JVM sera à court de mémoire.

Nous créons des références fantômes à un objet pour suivre le moment où l'objet est mis en file d'attente dans le ReferenceQueue. Une fois que vous savez que vous pouvez effectuer une finalisation fine. (Cela vous éviterait de ressusciter accidentellement l'objet car la référence fantôme ne vous donne pas le référent). Je vous suggère de lire cet article pour obtenir des détails détaillés à ce sujet.


Vous pouvez donc dire que les références fortes ont un pouvoir ultime (ne peuvent jamais être collectées par GC)

Les références souples sont puissantes que les références faibles (car elles peuvent échapper au cycle GC jusqu'à ce que JVM soit à court de mémoire)

Les références faibles sont encore moins puissantes que les références souples (car elles ne peuvent échapper à aucun cycle GC et seront récupérées si l'objet n'a pas d'autre référence forte).


Analogie de restaurant

  • Serveur - GC
  • Vous - Objet en tas
  • Zone / espace de restaurant - Espace de tas
  • Nouveau client - Nouvel objet qui veut une table au restaurant

Maintenant, si vous êtes un client solide (analogue à une référence forte), alors même si un nouveau client arrive au restaurant ou quoi que ce soit d'autre, vous ne quitterez jamais votre table (la zone de mémoire en tas). Le serveur n'a pas le droit de vous dire (ni même de vous demander) de quitter le restaurant.

Si vous êtes un client doux (analogue à soft reference), alors si un nouveau client arrive au restaurant, le serveur ne vous demandera pas de quitter la table à moins qu'il ne reste plus d'autre table vide pour accueillir le nouveau client. (En d'autres termes, le serveur vous demandera de quitter la table uniquement si un nouveau client entre et qu'il n'y a plus d'autre table pour ce nouveau client)

Si vous êtes un client faible (analogue à une référence faible), le serveur, à sa guise, peut (à tout moment) vous demander de quitter le restaurant: P

Lavish Kothari
la source
17

Les trois termes que vous avez utilisés sont principalement liés à l'éligibilité d'Object à la récupération de la mémoire.

Référence faible : c'est une référence qui n'est pas assez forte pour forcer l'objet à rester en mémoire. C'est le caprice du garbage collector de collecter cet objet pour le garbage collection. Vous ne pouvez pas forcer ce GC à ne pas le récupérer .

Référence souple : C'est plus ou moins la même chose que la référence faible. Mais vous pouvez dire qu'il contient l'objet un peu plus fortement que la référence faible du garbage collection.

Si les garbage collector collectent la référence faible dans le premier cycle de vie lui-même, ils collecteront la référence logicielle dans le prochain cycle de garbage collection.

Référence forte : C'est juste le contraire des deux types de références ci-dessus. Ils ressemblent moins à la collecte des déchets (la plupart du temps, ils ne sont jamais collectés.)

Vous pouvez vous référer au lien suivant pour plus d'informations:

http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/ref/Reference.html

Sabya
la source
3
Je pense que c'est faux - "Si les garbage collector collectent la référence faible dans le premier cycle de vie lui-même, ils collecteront la référence logicielle dans le prochain cycle de garbage collection." Ce n'est pas nécessairement le cas, comment pouvez-vous être si sûr qu'ils se produisent dans une exécution consécutive de GC? GC peut permettre aux objets référencés souples de vivre même dans la deuxième et la troisième exécution. Il n'y a pas de documentation pour cela, s'il y en a alors merci de mentionner le lien spécifiant.
Saurabh Patil
2
De plus, votre réponse est un peu vague, regardez cette phrase «C'est plus ou moins la même chose que la référence faible. Mais vous pouvez dire qu'il contient l'objet un peu plus fortement que la référence faible du garbage collection. ' - il pose clairement des questions sur la différence et non sur les similitudes, tous ces mots ajoutent plus de confusion que de clarté au sujet.
Saurabh Patil
@SaurabhPatil - Votre commentaire a manqué. Voici les réponses. 1. "il demande clairement la différence et non les similitudes" - Reportez-vous à la description de la question (pas "seulement" le titre) "Veuillez me donner quelques conseils, et s'il vous plaît me donner un exemple à décrire". 2. "Mais vous pouvez dire qu'il tient l'objet un peu plus ..." Je pense que SOF donne une option pour voter à la baisse et donner de nouvelles réponses aussi.
Sabya
11

Références fortes

Voici vos références d'objets habituelles que nous codons quotidiennement:

Employee emp = new Employee();

La variable «emp» contient une référence forte à un objet Employee et les objets qui sont accessibles via n'importe quelle chaîne de références fortes ne sont pas éligibles pour le garbage collection. Habituellement, c'est ce que vous voulez mais pas toujours. Supposons maintenant que nous récupérions beaucoup d'employés de la base de données dans une collection ou une carte, et que nous devions faire beaucoup de traitement sur eux régulièrement, donc pour maintenir les performances, nous les garderons dans le cache.

Dans la mesure où cela est bon, mais maintenant nous avons besoin de données différentes et nous n'avons pas besoin de ces objets Employee et ceux-ci ne sont référencés de nulle part sauf du cache. Ce qui provoque une fuite de mémoire car ces objets ne sont pas utilisés mais ne sont toujours pas éligibles pour le garbage collection et nous ne pouvons pas supprimer ces objets du cache car nous n'avons pas de référence à eux? Donc ici, soit nous devons vider tout le cache manuellement, ce qui est fastidieux, soit nous pourrions utiliser d'autres références de type, par exemple des références faibles.

Références faibles

Une référence faible n'épingle pas un objet en mémoire et sera GC dans le prochain cycle GC si elle n'est pas référencée à partir d'autres références. Nous pouvons utiliser la classe WeakReference qui est fournie par Java pour créer le type de caches ci-dessus, qui ne stockera pas les objets qui ne sont pas référencés ailleurs.

WeakReference<Cache> cache = new WeakReference<Cache>(data);

Pour accéder aux données, vous devez appeler cache.get (). Cet appel à get peut renvoyer null si la référence faible a été récupérée: vous devez vérifier la valeur retournée pour éviter les NPE. Java fournit des collections qui utilisent des références faibles, par exemple, la classe WeakHashMap stocke des clés (et non des valeurs) comme des références faibles. Si la clé est GC, la valeur sera également automatiquement supprimée de la carte.

Puisque les références faibles sont aussi des objets, nous avons besoin d'un moyen de les nettoyer (elles ne sont plus utiles lorsque l'objet qu'elles référençaient a été GC). Si vous passez un ReferenceQueue au constructeur pour une référence faible, le garbage collector ajoutera cette référence faible à ReferenceQueue avant qu'ils ne soient finalisés ou GC. Vous pouvez périodiquement traiter cette file d'attente et traiter les références mortes.

Références souples

Un SoftReference est comme un WeakReference mais il est moins susceptible d'être ramassé. Les références souples sont effacées à la discrétion du garbage collector en réponse à la demande de mémoire. La machine virtuelle garantit que toutes les références logicielles à des objets accessibles en douceur auront été effacées avant de lancer une erreur OutOfMemoryError.

Références fantômes

Les références fantômes sont les plus faibles de tous les types de références, appeler get sur elles renverra toujours null. Un objet est référencé de manière fantôme après avoir été finalisé, mais avant que sa mémoire allouée n'ait été récupérée, contrairement aux références faibles qui sont mises en file d'attente avant d'être finalisées ou les références fantômes GC sont rarement utilisées.

Alors, comment sont-ils utiles? Lorsque vous construisez une référence fantôme, vous devez toujours passer une ReferenceQueue. Cela indique que vous pouvez utiliser une référence fantôme pour voir quand votre objet est GC.

Hé, donc si des références faibles sont mises en file d'attente lorsqu'elles sont considérées comme finalisées mais pas encore GC, nous pourrions créer une nouvelle référence forte à l'objet dans le bloc du finaliseur et empêcher l'objet d'être GC. Oui, vous pouvez mais vous ne devriez probablement pas faire cela. Pour vérifier ce cas, le cycle GC se produira au moins deux fois pour chaque objet à moins que cet objet ne soit accessible que par une référence fantôme. C'est pourquoi vous pouvez manquer de tas même si votre mémoire contient beaucoup de déchets. Les références fantômes peuvent empêcher cela.

Vous pouvez en lire plus sur mon article Types de références en Java (Strong, Soft, Weak, Phantom) .

Naresh Joshi
la source
vous avez écrit que les réfrences faibles seront GC dans le prochain cycle si elles ne sont pas réfrenciées d'autres réfrences ... mais ne devrait-il pas se produire la même chose avec les réfrences stron? si l'on n'accède d'aucune façon à la réfraction stron, alors elle est effacée ... alors si oui, où est à nouveau la différence ...? #confused
filemonczyk
1
Si un objet est référencé à partir de disons s1 (fort) et s2 (fort), l'objet ne sera pas éligible pour le garbage collection tant que s1 et s2 ne seront pas référencés mais si l'objet est référencé à partir de s1 (faible) et s2 ( strong) alors l'objet sera éligible pour le garbage collection dans le prochain cycle GC lorsqu'il sera déréférencé de s2 uniquement, car s1 est une référence faible et si l'objet n'a pas d'autre référence que la faible, il est éligible pour GC
Naresh Joshi
10

4 degrés de référence - Strong, Weak, Soft, Phantom

Strong - est une sorte de référence, ce qui rend l'objet référencé non éligible pour GC. classes de constructeur. par exemple - StringBuilder

Faible - est une référence qui est éligible pour GC.

Soft - est une sorte de référence dont l'objet est éligible pour GC jusqu'à ce que la mémoire soit disponible. Idéal pour le cache d'image. Il les conservera jusqu'à ce que la mémoire soit disponible.

Phantom - est une sorte de référence dont l'objet est directement éligible pour GC. Utilisé uniquement pour savoir quand un objet est supprimé de la mémoire.

les usages:

  1. Vous permet d'identifier quand un objet est exactement supprimé de la mémoire.

  2. lorsque la finalize()méthode est surchargée, GC peut ne pas se produire en temps opportun pour les objets éligibles GC des deux classes. Donc, la référence fantôme les rend éligibles pour GC avant finalize(), c'est pourquoi vous pouvez obtenir OutOfMemoryErrors même lorsque la plupart du tas est des ordures.

Les références faibles sont idéales pour implémenter les modules de cache.

Preetham RU
la source