Quelle est la différence entre java.lang.ref.WeakReference
et java.lang.ref.SoftReference
?
Quelle est la différence entre java.lang.ref.WeakReference
et java.lang.ref.SoftReference
?
Réponses:
De Comprendre les références faibles , par Ethan Nicholas:
Références faibles
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. Vous créez une référence faible comme celle-ci:
WeakReference weakWidget = new WeakReference(widget);
puis ailleurs dans le code que vous pouvez utiliser
weakWidget.get()
pour obtenir l'Widget
objet réel . Bien sûr, la référence faible n'est pas assez forte pour empêcher la récupération de place, vous pouvez donc trouver (s'il n'y a pas de références fortes au widget) quiweakWidget.get()
commence soudainement à revenirnull
....
Références douces
Une référence douce 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 jeté au prochain cycle de collecte des ordures, mais un objet qui est facilement accessible restera généralement un certain temps.
SoftReferences
ne sont pas tenus de se comporter différemmentWeakReferences
, mais dans la pratique, les objets facilement accessibles sont généralement conservés tant que la mémoire est abondante. Cela en fait une excellente base pour un cache, tel que le cache d'image décrit ci-dessus, car vous pouvez laisser le garbage collector s'inquiéter à la fois de la façon dont les objets sont accessibles (un objet fortement accessible ne sera jamais supprimé du cache) et de sa gravité. a besoin de la mémoire qu'ils consomment.
Et Peter Kessler a ajouté dans un commentaire:
Le Sun JRE traite les SoftReferences différemment des WeakReferences. Nous essayons de nous accrocher à l'objet référencé par une SoftReference s'il n'y a pas de pression sur la mémoire disponible. Un détail: la stratégie pour les JRE "-client" et "-server" est différente: le JRE -client essaie de garder votre encombrement petit en préférant effacer les SoftReferences plutôt que de développer le tas, tandis que le JRE -server essaie de garder votre performances élevées en préférant étendre le tas (si possible) plutôt que d'effacer les références logicielles. Une taille unique ne convient pas à tous.
Les références faibles sont collectées 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 bons pour conserver une référence à un objet pour lequel votre programme conserve également (fortement référencé) des "informations associées", comme les informations de réflexion mises en cache sur une classe, ou un wrapper pour un objet, etc. Tout ce qui fait aucun sens à garder après que l'objet auquel il est associé soit 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érence que votre code interroge quelque part, et elle supprime également les objets associés. Autrement dit, vous conservez des informations supplémentaires sur un objet, mais ces informations ne sont pas nécessaires une fois que l'objet auquel il fait référence disparaît. Réellement, dans certaines situations, vous pouvez même sous-classer WeakReference et conserver les informations supplémentaires associées sur l'objet dans les champs de la sous-classe WeakReference. Une autre utilisation typique de WeakReference est en conjonction avec Maps pour conserver les instances canoniques.
Les références logicielles, d'autre part, sont bonnes pour la mise en cache des ressources externes et recréables car le GC retarde généralement leur effacement. Il est cependant garanti que toutes les SoftReferences seront effacées avant que OutOfMemoryError ne soit levée, donc elles ne peuvent théoriquement pas provoquer un OOME [*].
Un exemple typique de cas d'utilisation consiste à conserver une forme analysée d'un contenu à partir d'un fichier. Vous implémenteriez un système dans lequel vous chargeriez un fichier, l'analyseriez et conserveriez une SoftReference à l'objet racine de la représentation analysée. La prochaine fois que vous aurez besoin du fichier, vous essaierez de le récupérer via SoftReference. Si vous pouvez le récupérer, vous vous êtes épargné une autre charge / analyse, et si le GC l'a effacé entre-temps, vous le rechargez. De cette façon, vous utilisez de la mémoire libre pour l'optimisation des performances, mais ne risquez pas un OOME.
Maintenant pour le [*]. Garder une SoftReference ne peut pas provoquer un OOME en soi. Si, d'autre part, vous utilisez par erreur SoftReference pour une tâche, une WeakReference est destinée à être utilisée (à savoir, vous conservez les informations associées à un objet en quelque sorte fortement référencées et les jetez lorsque l'objet Reference est effacé), vous pouvez exécuter OOME comme votre code qui interroge la ReferenceQueue et rejette les objets associés peut ne pas s'exécuter en temps opportun.
Ainsi, la décision dépend de l'utilisation - si vous mettez en cache des informations coûteuses à construire, mais néanmoins reconstructibles à partir d'autres données, utilisez des références logicielles - si vous conservez une référence à une instance canonique de certaines données, ou si vous souhaitez avoir une référence à un objet sans le "posséder" (l'empêchant ainsi d'être GC'd), utiliser une référence faible.
WeakReference
est que dans les endroits où l'on devrait l'utiliser, le fait que l'on puisse rester valide pendant un certain temps après que la référence soit hors de portée peut être tolérable, mais n'est pas souhaitable.
WeakReference
pour observer les exécutions du GC. Voir l'élaboration: stackoverflow.com/a/46291143/632951
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éré de la collecte par GC. c.-à-d. ne jamais ramasser les ordures.
Une référence logicielle peut être collectée par le garbage collector, mais ne sera probablement pas collectée tant que sa mémoire n'est pas nécessaire. c.-à-d. les ordures ramassent avant OutOfMemoryError
.
Une référence faible est une référence qui ne protège pas un objet référencé de la collecte par GC. c.-à-d. que les ordures se collectent lorsqu'aucune référence forte ou douce.
Une référence fantôme est une référence à un objet référencée fantôme après sa finalisation, mais avant que sa mémoire allouée ne soit récupérée.
Analogie: Supposons qu'une JVM est un royaume, Object est un roi du royaume et GC est un attaquant du royaume qui essaie de tuer le roi (objet).
until memory is available
n'a pas de sens. Tu veux dire is eligible for collection by garbage collector, but probably won't be collected until its memory is needed for another use
?
Référence faible http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ref/WeakReference.html
Principe: weak reference
est lié à la collecte des ordures. Normalement, un objet en ayant un ou plusieurs reference
ne sera pas éligible pour la récupération de place.
Le principe ci-dessus n'est pas applicable lorsqu'il l'est weak reference
. Si un objet n'a qu'une référence faible avec d'autres objets, il est prêt pour la collecte des ordures.
Regardons l'exemple ci-dessous: Nous avons un Map
avec des objets où Key fait référence à 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 que nous avons fait emp = null
. La Map
tenue la clé n'a pas de sens ici comme il est null
. Dans la situation ci-dessus, l'objet n'est pas récupéré.
WeakHashMap
WeakHashMap
est celui où les entrées ( key-to-value mappings
) seront supprimées lorsqu'il ne sera plus possible de les récupérer à partir du Map
.
Permettez-moi de montrer l'exemple ci-dessus 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: a pris 20 calls to System.gc()
pour résultat aMap size
: 0.
WeakHashMap
n'a que des références faibles aux clés, pas des références fortes comme les autres Map
classes. Il y a des situations auxquelles vous devez faire attention lorsque la valeur ou la clé est fortement référencée bien que vous l'ayez utilisée WeakHashMap
. Cela peut être évité en enveloppant l'objet dans une référence faible .
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 souples.
Soft Reference
est légèrement plus fort que la référence faible. La référence logicielle permet le ramasse-miettes, mais demande au ramasse-miettes de l'effacer uniquement 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 avec les objets peu accessibles - au lieu de cela, il ne collecte les objets facilement accessibles que s'il "a vraiment besoin" de la mémoire. Les références souples sont une façon de dire au garbage collector: "Tant que la mémoire n'est pas trop serrée, je voudrais garder cet objet autour. Mais si la mémoire devient vraiment serrée, allez-y et récupérez-la et je traiterai avec ça." Le garbage collector est nécessaire pour effacer toutes les références logicielles avant de pouvoir lancer OutOfMemoryError
.
NullPointerException
dansaMap.get().put(...)
.
WeakHashMap
exemple (puisque c'est le premier qui démontre un comportement faible). Regardez le document pour "WeakHashMap": "An entry in a WeakHashMap will automatically be removed when its key is no longer in ordinary use. "
L'intérêt de l'utilisation de WeakHashMap est que vous n'avez pas à déclarer / transmettre un WeakReference; le WeakHashMap le fait pour vous, en interne. docs.oracle.com/javase/7/docs/api/java/util/WeakHashMap.html
WeakHashMap
en action, avec un exemple d'application montrant comment les entrées sont supprimées uniquement après l' exécution de la récupération de place, voir ma réponse à la question, WeakHashMap est-il en constante croissance, ou efface-t-il les clés de récupération? .
La seule vraie différence entre une référence douce et une référence faible est que
le garbage collector utilise des algorithmes pour décider de récupérer ou non un objet facilement accessible, mais récupère toujours un objet faiblement accessible.
SoftReference
est conçu pour les caches. Lorsqu'il est constaté qu'un a fait WeakReference
référence à un objet autrement 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 libre 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 en autant de secondes qu'il y a de mégaoctets de mémoire libre sur le tas Java (configurable, le serveur HotSpot vérifie le maximum de tas possible défini par -Xmx
). SoftReference
s sera effacé avant OutOfMemoryError
son lancement, sauf indication contraire.
java.lang
. Un tel abus de synonymes ne fait de bien à personne.
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 n'avez que des références faibles à un objet (sans références fortes), alors l'objet sera récupéré par GC lors du tout prochain cycle GC.
Si vous n'avez que des références logicielles à un objet (sans références fortes), l'objet ne sera récupéré par GC que lorsque JVM manque de mémoire.
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 manque de mémoire)
Les références faibles sont encore moins puissantes que les références douces (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).
Restaurant Analogy
Maintenant, si vous êtes un client fort (analogue à une référence forte), alors même si un nouveau client vient au restaurant ou quoi qu'il arrive, vous ne quitterez jamais votre table (la zone de mémoire sur le 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 à une référence douce), alors si un nouveau client vient au restaurant, le serveur ne vous demandera pas de quitter la table à moins qu'il ne reste plus de table vide pour accueillir le nouveau client. (En d'autres termes, le serveur vous demandera de quitter la table uniquement si un nouveau client intervient 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
Selon le document , les WeakReferences lâches doivent être effacées par un GC en cours d'exécution.
Selon le document , les références logicielles lâches doivent être effacées 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 références logicielles sont utiles.Les caches sensibles à la mémoire utilisent des références logicielles, pas des références faibles.
weak_ref.get()
. Quand c'est le cas null
, vous apprenez qu'entre cette durée, le GC a fonctionné.
Quant à une mauvaise utilisation de WeakReference, la liste est interminable:
un hack moche pour implémenter une référence souple de priorité 2 de sorte que vous n'ayez pas à en écrire une, mais cela ne fonctionne pas comme prévu car le cache serait effacé à chaque exécution du GC, même lorsqu'il y a de la mémoire disponible. Voir https://stackoverflow.com/a/3243242/632951 pour les phails. (D'ailleurs, que se passe-t-il si vous avez besoin de plus de 2 niveaux de priorité de cache? Vous auriez toujours besoin d'une vraie bibliothèque pour cela.)
un hack moche pour associer des données à un objet d'une classe existante, mais cela crée une fuite de mémoire (OutOfMemoryError) lorsque votre GC décide de faire une pause après la création de vos faibles références. En outre, c'est au-delà de la laideur: une meilleure approche consiste à utiliser des tuples.
un hack moche pour associer des données à un objet d'une classe existante, où la classe a le culot de se rendre non sous-classable, et est utilisé dans un code de fonction existant que vous devez appeler. Dans un tel cas, la solution appropriée consiste soit à éditer la classe et à la rendre sous-classable, soit à éditer la fonction et à lui faire prendre une interface à la place d'une classe, ou à utiliser une fonction alternative.
equals()
n'est qu'une identité d'objet? Les références logicielles semblent être un gaspillage là-bas, car une fois qu'un objet clé n'est plus fortement accessible, personne ne cherchera plus jamais ce mappage.
Les six types d'états d'accessibilité aux objets en Java:
Pour plus de détails: https://www.artima.com/insidejvm/ed2/gc16.html «réduire
Il faut savoir qu'un objet faiblement référencé ne sera collecté que s'il a UNIQUEMENT des références faibles. S'il a autant qu'une référence forte, il n'est pas collecté quel que soit le nombre de références faibles qu'il possède.
Pour donner un aspect d'utilisation de la mémoire en action, j'ai fait une expérience avec des références fortes, douces, faibles et fantômes sous forte charge avec des objets lourds en les conservant jusqu'à la fin du programme. Puis suivi de l'utilisation du tas et du comportement du GC . Ces mesures peuvent varier au cas par cas, mais donnent certainement une compréhension de haut niveau. Voici les résultats.
Comportement du tas et du GC sous une charge élevée
Vous pouvez obtenir des graphiques plus détaillés , des statistiques, des observations pour cette expérience ici .
WeakReference : les objets qui ne sont que faiblement référencés sont collectés à chaque cycle GC (mineur ou complet).
SoftReference : lorsque des objets qui sont uniquement référencés en douceur sont collectés, cela dépend:
-XX: indicateur SoftRefLRUPolicyMSPerMB = N (la valeur par défaut est 1000, alias 1 seconde)
Quantité de mémoire libre dans le tas.
Exemple:
Ensuite, l'objet qui n'est référencé que par SoftReference sera collecté si la dernière fois lors de son accès est supérieure à 10 secondes.