web-dev-qa-db-fra.com

Quelle est la différence entre SoftReference et WeakReference en Java?

Quelle est la différence?

743
driekken

De Comprendre les faibles références , par Ethan Nicholas:

Références faibles

Un référence faible, tout simplement, est un référence qui n'est pas assez forte pour forcer un objet à rester en mémoire . Les faibles références vous permettent de tirer profit de la capacité du ramasse-miettes à déterminer l'accessibilité pour vous, de sorte que vous ne pas le faire vous-même. Vous créez une référence faible comme celle-ci:

WeakReference weakWidget = new WeakReference(widget);

et alors ailleurs dans le code, vous pouvez utiliser weakWidget.get() pour obtenir le .__ réel. Widget object. Bien sûr le faible la référence n'est pas assez forte pour empêcher la collecte des ordures, de sorte que vous pouvez trouve (s'il n'y a pas de fortes références au widget) que weakWidget.get() démarre soudainement retournant null.

...

Références douces

Un référence souple est exactement comme un référence faible, sauf que c'est moins désireux de jeter l'objet à auquel il se réfère. Un objet qui est faiblement accessible (les références les plus fortes à celle-ci sont WeakReferences) sera jeté à la prochaine poubelle cycle de collecte, mais un objet qui est généralement accessible rester pendant un moment.

SoftReferences ne sont pas requis à se comporter différemment que WeakReferences, mais en pratique doucement les objets accessibles sont généralement conservé tant que la mémoire est dedans offre abondante. Cela les rend un excellente base pour une cache, telle comme le cache d'image décrit ci-dessus, puisque vous pouvez laisser la poubelle collectionneur s'inquiéter à la fois comment accessibles les objets sont (un objet fortement accessible sera jamais être supprimé du cache) et à quel point il est nécessaire. la mémoire qu'ils consomment.

Et Peter Kessler a ajouté dans un commentaire:

Sun JRE traite les SoftReferences différemment des WeakReferences. Nous essayons de conserver les objets référencés par SoftReference s'il n'y a pas de pression sur la mémoire disponible. Un détail: les règles pour les JRE "-client" et "-server" sont différentes: le JRE -client essaie de garder votre empreinte réduite en préférant supprimer les SoftReferences plutôt que d’étendre le tas, alors que le performances élevées en préférant agrandir le tas (si possible) plutôt que de supprimer les SoftReferences. Une taille unique ne convient pas à tous.

859
Michael Myers

Les références faibles sont recueillies avec impatience. Si GC trouve qu'un objet est faiblement accessible (accessible uniquement via des références faibles), il effacera immédiatement les références faibles à cet objet. En tant que tels, ils sont utiles pour Conserver une référence à un objet pour lequel votre programme conserve également (Fortement référencé) "informations associées" quelque part, comme en cache Des informations de réflexion sur une classe ou un wrapper pour un objet, etc. .. Tout ce qui n'a aucun sens de conserver après l'objet auquel il est associé est associé à GC-ed. Lorsque la référence faible est effacée, elle est mise en file d'attente dans une file d'attente de références Que votre code interroge quelque part et les objets associés à Sont également ignorés. En d'autres termes, vous conservez des informations supplémentaires sur un objet , Mais ces informations ne sont plus nécessaires une fois que l'objet auquel il fait référence disparaît. En fait, dans certaines situations, vous pouvez même créer une sous-classe WeakReference et conserver les informations supplémentaires associées à l’objet dans les champs de la sous-classe WeakReference. Une autre utilisation typique de WeakReference est associée à Maps pour conserver des instances canoniques.

Les SoftReferences, d’autre part, sont utiles pour la mise en cache de ressources externes pouvant être reconstituées Le GC retardant généralement leur effacement. Il est cependant garanti que toutes les SoftReferences seront effacées avant que OutOfMemoryError ne soit renvoyé. Par conséquent, ils Ne peuvent théoriquement pas causer un OOME [*].

Un exemple typique de cas d'utilisation consiste à conserver une forme analysée d'un contenu à partir d'un fichier Vous mettriez en place un système dans lequel vous chargeriez un fichier, l'analyseriez et garderiez Un SoftReference dans l'objet racine de la représentation analysée. La prochaine foisvous avez besoin du fichier, vous essayerez de le récupérer via SoftReference. Si vous pouvez le récupérer, vous vous êtes épargné un autre chargement/analyse, et si le GC. L'a effacé dans l'intervalle, vous le rechargez. De cette façon, vous utilisez de la mémoire libre Pour optimiser les performances, mais ne courez pas le risque de tomber sur OOME.

Maintenant pour le [*]. Garder un SoftReference ne peut pas causer un OOME en soi. Si D’autre part, vous utilisez par erreur SoftReference pour une tâche, un WeakReference est utiliséà utiliser (c’est-à-dire que vous conservez en quelque sorte les informations associées à un objet Fortement référencées, et les ignorez lorsque l'objet de référence est effacé), vous pouvez vous heurter à OOME car votre code qui interroge ReferenceQueue et ignore les objets associés risque de ne pas s'exécuter dans les délais impartisfashion.

Ainsi, la décision dépend de l'utilisation - si vous mettez en cache des informations coûteuses à construire, mais que Néanmoins reconstructibles à partir d'autres données, utilisez des références logicielles - si vous conservez une référence à un nom canonique. exemple de certaines données, ou.vous voulez avoir une référence à un objet sans le "posséder" (donc l'empêcher de l'être), utilisez une référence faible.

194
driekken

En Java; ordre du plus fort au plus faible, il y a: Fort, Doux, Faible et Fantôme 

Une référence forte est une référence normale qui protège l'objet référencé de la collecte par GC. c'est-à-dire que les ordures ne sont jamais ramassées. 

Une référence Soft est éligible à la collecte par le ramasse-miettes, mais ne sera probablement pas collectée tant que sa mémoire ne sera pas nécessaire. c'est-à-dire que les ordures sont collectées avant OutOfMemoryError

Une référence Weak est une référence qui ne protège pas un objet référencé de la collection par GC. c'est-à-dire que les ordures sont collectées lorsqu'aucune référence forte ou douce n'est fournie. 

Une référence Phantom est une référence à un objet qui est référencé de manière fantomatique après sa finalisation, mais avant que sa mémoire allouée n'ait été récupérée.

La source

Analogie: Supposons qu'une JVM est un royaume, Object est un roi du royaume et GC est un attaquant du royaume qui tente de tuer le roi (objet).

  • Quand King est Strong, GC ne peut pas le tuer. 
  • Quand King est Soft, GC l'attaque mais King règne sur le royaume avec protection jusqu'à ce que les ressources soient disponibles. 
  • Lorsque King est faible, GC l’attaque mais dirige le royaume sans protection. 
  • Quand le roi est Phantom, GC l'a déjà tué mais le roi est disponible via son âme.
119
Premraj

Référence faiblehttp://docs.Oracle.com/javase/1.5.0/docs/api/Java/lang/ref/WeakReference.html

Principe:weak reference est lié à la récupération de place. Normalement, un objet ayant une ou plusieurs variables reference ne sera pas éligible pour la récupération de place.
Le principe ci-dessus n'est pas applicable quand il s'agit de weak reference. Si un objet n'a qu'une référence faible avec d'autres objets, il est alors prêt pour la récupération de place.

Regardons l'exemple ci-dessous: Nous avons une Map avec des objets où Key est la référence d'un objet. 

import Java.util.HashMap;   
public class Test {

    public static void main(String args[]) {
        HashMap<Employee, EmployeeVal> aMap = new 
                       HashMap<Employee, EmployeeVal>();

        Employee emp = new Employee("Vinoth");
        EmployeeVal val = new EmployeeVal("Programmer");

        aMap.put(emp, val);

        emp = null;

        System.gc();
        System.out.println("Size of Map" + aMap.size());

    }
}

Maintenant, pendant l'exécution du programme, nous avons créé emp = null. La Map détenant la clé n'a pas de sens ici car elle est null. Dans la situation ci-dessus, l'objet n'est pas récupéré. 

WeakHashMap

WeakHashMap est un endroit où les entrées (key-to-value mappings) seront supprimées lorsqu'il ne sera plus possible de les récupérer à partir de Map.

Me laisser montrer l'exemple ci-dessus même avec WeakHashMap

import Java.util.WeakHashMap;

public class Test {

    public static void main(String args[]) {
        WeakHashMap<Employee, EmployeeVal> aMap = 
                    new WeakHashMap<Employee, EmployeeVal>();

        Employee emp = new Employee("Vinoth");
        EmployeeVal val = new EmployeeVal("Programmer");

        aMap.put(emp, val);

        emp = null;

        System.gc();
        int count = 0;
        while (0 != aMap.size()) {
            ++count;
            System.gc();
        }
        System.out.println("Took " + count
                + " calls to System.gc() to result in weakHashMap size of : "
                + aMap.size());
    }
}

Sortie: Il a fallu 20 calls to System.gc() pour générer aMap size sur: 0. 

WeakHashMap n'a que des références faibles aux clés, pas des références fortes comme les autres classes Map. Certaines situations doivent être prises en compte lorsque la valeur ou la clé est fortement référencée bien que vous ayez utilisé WeakHashMap. Cela peut être évité en encapsulant l'objet dans un WeakReference.

import Java.lang.ref.WeakReference;
import Java.util.HashMap;

public class Test {

    public static void main(String args[]) {
        HashMap<Employee, EmployeeVal> map = 
                      new HashMap<Employee, EmployeeVal>();
        WeakReference<HashMap<Employee, EmployeeVal>> aMap = 
                       new WeakReference<HashMap<Employee, EmployeeVal>>(
                map);

        map = null;

        while (null != aMap.get()) {
            aMap.get().put(new Employee("Vinoth"),
                    new EmployeeVal("Programmer"));
            System.out.println("Size of aMap " + aMap.get().size());
            System.gc();
        }
        System.out.println("Its garbage collected");
    }
}

Références molles.

Soft Reference est légèrement plus fort que la référence faible. La référence souple permet la récupération de place, mais demande au récupérateur de place de l'effacer seulement s'il n'y a pas d'autre option. 

Le ramasse-miettes ne collecte pas de manière agressive les objets facilement accessibles comme il le fait pour les objets faiblement accessibles. Il ne collecte les objets accessibles que s'il a réellement besoin de la mémoire. Les références symboliques sont un moyen de dire au ramasse-miettes: "Tant que la mémoire n'est pas trop étroite, j'aimerais conserver cet objet. Mais si la mémoire devient trop petite, allez-y, récupérez-la et je traiterai avec ça." Le ramasse-miettes est nécessaire pour effacer toutes les références logicielles avant de pouvoir lancer OutOfMemoryError.

68
Thalaivar

La seule vraie différence entre une référence souple et une référence faible est que 

le ramasse-miettes utilise des algorithmes pour décider si récupérer un objet facilement accessible, mais récupère toujours un objet faible objet accessible.

45
Samir Mangroliya

SoftReference est conçu pour les caches. Lorsqu'il est constaté qu'une WeakReference fait référence à un objet inaccessible, il sera immédiatement effacé. SoftReference peut être laissé tel quel. En règle générale, il existe un algorithme relatif à la quantité de mémoire disponible et au dernier temps utilisé pour déterminer si elle doit être effacée. L'algorithme Sun actuel consiste à effacer la référence si elle n'a pas été utilisée pendant autant de secondes qu'il reste des mégaoctets de mémoire libre sur le segment de mémoire Java (configurable, le serveur HotSpot configurable vérifie le segment de mémoire maximal possible défini par -Xmx). SoftReferences sera effacé avant que OutOfMemoryError ne soit lancé, à moins que vous ne puissiez l'atteindre.

22

La seule vraie différence

Par le doc , desserrez WeakReferences must par un GC en cours d'exécution.

Pour le doc , les SoftReferences en vrac doivent être effacés avant que le MOO ne soit lancé.

C'est la seule vraie différence. Tout le reste ne fait pas partie du contrat. (Je suppose que les derniers documents sont contractuels.)

Les SoftReferences sont utiles. Les caches sensibles à la mémoire utilisent SoftReferences, pas WeakReferences .


La seule correcte utilisation de WeakReference consiste à observer le déroulement du CPG. Pour ce faire, vous créez un nouveau WeakReference dont l'objet sort immédiatement de la portée, puis vous essayez d'extraire null de weak_ref.get(). Quand c'est null, vous apprenez qu'entre cette durée, le GC s'est exécuté.

En ce qui concerne incorrect utilisation de WeakReference, la liste est sans fin:

  • un bidouillage médiocre pour implémenter une priorité de priorité 2 telle que vous n'avez pas à en écrire un, encore _ cela ne fonctionne pas comme prévu car le cache serait effacé à la toutes exécution du GC , même quand il y a de la mémoire disponible. Voir https://stackoverflow.com/a/3243242/632951 pour les phails. (En outre, si vous avez besoin de plus de 2 niveaux de priorité de cache? Vous aurez toujours besoin d'une vraie bibliothèque pour cela.)

  • un bidouillage moche pour associer des données à un objet d'une classe existante, encore il crée une fuite de mémoire (OutOfMemoryError) lorsque votre GC décide de faire une pause après la création de vos références faibles. En outre, cela va au-delà de laide: une meilleure approche consiste à utiliser des n-uplets. 

  • un bidouillage moche pour associer des données à un objet d'une classe existante, où la classe a le courage de se rendre non-sous-classable, et est utilisée dans un code de fonction existant que vous devez appeler. Dans ce cas, la solution appropriée consiste à éditer la classe et à la rendre sous-classable, ou à éditer la fonction et à lui faire prendre une interface au lieu d'une classe, ou d'utiliser une fonction alternative.

7
Pacerier

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 uniquement faibles références à un objet (sans références fortes), l'objet sera récupéré par GC au cours du prochain cycle de GC.

Si vous ne disposez que de soft references à 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.


Donc, vous pouvez dire que, les références fortes ont pouvoir ultime (ne peut jamais être collecté par GC)

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

Les références faibles sont même 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 au restaurant

  • Serveur - GC 
  • You - Objet en tas 
  • Zone de restauration/espace - Heap Space
  • Nouveau client - Nouvel objet qui veut une table dans un restaurant

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

Si vous êtes un {client léger} _ (comme une référence virtuelle), si un nouveau client arrive dans le restaurant, le serveur ne vous demandera pas de quitter la table à moins qu'il ne reste plus de table vide pour accueillir le client. nouveau client. (En d'autres termes, le serveur vous demandera de quitter la table uniquement si un nouveau client intervient et s'il ne reste aucune autre table pour ce nouveau client)

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

4
Lavish Kothari

Les six types d'états d'accessibilité d'objets en Java -

  1. Fortles objets joignables - GC ne le sera pas collecter (récupérer la mémoire occupée par) ce type d'objets. Ceux-ci sont accessibles via un nœud racine ou un autre objet très accessible (c'est-à-dire via des variables locales, des variables de classe, des variables d'instance, etc.)
  2. Softles objets joignables - GC peut tenter de collecter ce type d'objets en fonction des conflits de mémoire. Ceux-ci sont accessibles à partir de la racine via un ou plusieurs objets de référence logiciels
  3. Faibleles objets joignables - GC doit collectionne ce type d'objets. Ceux-ci sont accessibles depuis la racine via un ou plusieurs objets de référence faibles
  4. Resurrectable objets - GC est déjà en train de collecter ces objets. Mais ils peuvent retourner à l'un des états - Fort/Doux/Faible} par l'exécution d'un finaliseur
  5. Phantomly object accessible - GC est déjà en train de collecter ces objets et a décidé de ne pas être ressuscité par aucun finaliseur (s'il déclare une méthode finalize () ont été exécutés)} _. Ceux-ci sont accessibles depuis la racine via un ou plusieurs objets de référence fantômes
  6. Injoignable objet - Un objet n'est ni fort, doucement, faiblement accessible, ni fantomatique, et ne peut pas être ressuscité. Ces objets sont prêts à être récupérés 

Pour plus de détails: https://www.artima.com/insidejvm/ed2/gc16.html «collapse 

3
V.Vidyasagar

Pour donner un aspect d'utilisation de la mémoire en action, j'ai fait une expérience avec des références Fort, Doux, Faible et Fantôme sous une charge lourde avec des objets lourds en les conservant jusqu'à la fin du programme. Puis surveillait l'utilisation du segment de mémoire et le comportement de la GC . Ces métriques peuvent varier au cas par cas mais donnent certainement une compréhension de haut niveau. Vous trouverez ci-dessous les résultats.

Comportement de tas et de GC sous forte charge

  • Référence forte/dure - Au fur et à mesure que le programme se poursuivait, JVM ne pouvait pas collecter l'objet référencé fort. Finalement fini dans "Java.lang.OutOfMemoryError: Java espace de tas"
  • Référence logicielle - Au fur et à mesure de la progression du programme, l'utilisation du segment de mémoire n'a cessé de croître, mais l'ancienne génération GC a eu lieu alors qu'il était proche du segment de mémoire maximal. La GC a démarré un peu plus tard après le début du programme.
  • Référence faible - Au début du programme, les objets ont commencé à être finalisés et à être collectés presque immédiatement. La plupart des objets ont été collectés lors de la collecte des ordures ménagères de la jeune génération.
  • Référence fantôme - Similaire à la référence faible, les objets référencés fantômes ont également commencé à être finalisés et les ordures immédiatement collectées. Il n'y avait pas de GC ancienne génération et tous les objets étaient collectés dans la collecte des ordures de la jeune génération elle-même.

Vous pouvez obtenir plus de détails graphiques, statistiques, observations pour cette expérience ici .

0
Ravi K

Sachez qu’un objet faiblement référencé ne sera collecté que s’il contient UNIQUEMENT des références faibles. S'il y a une seule référence forte, il ne sera pas collecté, peu importe le nombre de références faibles qu'il possède.

0
Fai Lau

WeakReference : les objets qui ne sont que très faiblement référencés sont collectés à chaque cycle GC (mineur ou complet).

SoftReference : la collecte d'objets qui ne sont que faiblement référencés dépend de: 

  1. -XX: indicateur SoftRefLRUPolicyMSPerMB = N (la valeur par défaut est 1000, soit 1 seconde) 

  2. Quantité de mémoire libre dans le tas. 

    Exemple: 

    • heap dispose de 10 Mo d’espace libre (après mise en place complète);
    • -XX: SoftRefLRUPolicyMSPerMB = 1000 

    Ensuite, un objet référencé uniquement par SoftReference sera collecté si le dernier accès a été supérieur à 10 secondes.

0
Artem Petrov