¿Cuál es la diferencia entre SoftReference y WeakReference en Java?
weak-references soft-references (11)
La única diferencia real
De acuerdo con el documento , un GC en ejecución debe borrar las WeakReferences sueltas.
Según el documento , se deben eliminar las referencias de software sueltas antes de lanzar la OOM.
Esa es la única diferencia real. Todo lo demás no es parte del contrato. (Asumiré que los últimos documentos son contractuales.)
Las referencias suaves son útiles. Los cachés sensibles a la memoria utilizan SoftReferences, no WeakReferences.
El único uso correcto de WeakReference es observar el funcionamiento del GC. Para hacer esto, cree una nueva WeakReference cuyo objeto salga inmediatamente del ámbito, luego intente sacar el nulo deweak_ref.get()
. Cuando es null
, aprendes que entre esta duración, se ejecutó el GC. En cuanto al uso incorrecto de WeakReference, la lista es interminable:
un mal truco para implementar la referencia suave de prioridad 2 de modo que no tenga que escribir una, pero no funciona como se esperaba porque la memoria caché se borraría en cada ejecución del GC, incluso cuando haya memoria de repuesto. Ver https://stackoverflow.com/a/3243242/632951 para phails. (Además, ¿qué sucede si necesita más de 2 niveles de prioridad de caché? Todavía necesita una biblioteca real para ello).
un pésimo truco para asociar datos con un objeto de una clase existente, sin embargo, crea una pérdida de memoria (OutOfMemoryError) cuando su GC decide tomar un descanso después de que se crean sus referencias débiles. Además, está más allá de lo feo: un mejor enfoque es utilizar tuplas.
un pésimo truco para asociar datos con un objeto de una clase existente, donde la clase tiene el descaro de convertirse en no subclasificable, y se utiliza en un código de función existente al que debe llamar. En tal caso, la solución adecuada es editar la clase y hacerla subclasificable, o editar la función y hacer que tome una interfaz en lugar de una clase, o usar una función alternativa.
¿Cual es la diferencia?
De Understanding Weak References , por Ethan Nicholas:
Referencias débiles
Una referencia débil , en pocas palabras, es una referencia que no es lo suficientemente fuerte como para obligar a un objeto a permanecer en la memoria. Las referencias débiles le permiten aprovechar la capacidad del recolector de basura para determinar la accesibilidad para usted, por lo que no tiene que hacerlo usted mismo. Usted crea una referencia débil como esta:
WeakReference weakWidget = new WeakReference(widget);
y luego en otro lugar del código, puede usar
weakWidget.get()
para obtener el objetoWidget
real. Por supuesto, la referencia débil no es lo suficientemente fuerte como para evitar la recolección de elementos no utilizados, por lo que puede encontrar (si no hay referencias sólidas al widget) queweakWidget.get()
repente comienza a devolver elnull
....
Referencias blandas
Una referencia suave es exactamente igual a una referencia débil, excepto que está menos dispuesta a tirar el objeto al que hace referencia. Un objeto al que solo se puede
WeakReferences
débilmente (las referencias más fuertes a él sonWeakReferences
) se descartará en el siguiente ciclo de recolección de basura, pero un objeto al que seWeakReferences
se quedará por un tiempo.
SoftReferences
se requiere que lasSoftReferences
se comporten de manera diferente a lasWeakReferences
, pero en la práctica, los objetos deWeakReferences
acceso generalmente se retienen siempre que la memoria sea abundante. Esto los convierte en una base excelente para una memoria caché, como la memoria caché de imagen descrita anteriormente, ya que puede dejar que el recolector de basura se preocupe por la accesibilidad de los objetos (un objeto muy accesible nunca se eliminará de la memoria caché) y lo mal que está Necesita la memoria que están consumiendo.
Y Peter Kessler agregó en un comentario:
El Sun JRE trata a las referencias de forma diferente a las referencias de debilidad. Intentamos aferrarnos al objeto al que hace referencia SoftReference si no hay presión en la memoria disponible. Un detalle: la política para los JRE "-cliente" y "-servidor" son diferentes: el JRE -cliente intenta mantener su huella pequeña prefiriendo borrar las referencias de referencia en lugar de expandir el montón, mientras que el JRE-servidor intenta mantener su alto rendimiento al preferir expandir el montón (si es posible) en lugar de borrar las referencias de software. Una talla no sirve para todos.
Este article puede ser muy útil para comprender referencias fuertes, suaves, débiles y fantasma.
Para darle un resumen,
Si solo tiene referencias débiles a un objeto (sin referencias fuertes), el GC lo reclamará en el siguiente ciclo de GC.
Si solo tiene referencias blandas a un objeto (sin referencias sólidas), el objeto será reclamado por GC solo cuando la JVM se quede sin memoria.
Así que puedes decir que, las referencias fuertes tienen un poder máximo (nunca pueden ser recopiladas por GC)
Las referencias blandas son poderosas que las débiles (ya que pueden escapar del ciclo de GC hasta que la JVM se quede sin memoria)
Las referencias débiles son incluso menos poderosas que las referencias blandas (ya que no pueden superar ningún ciclo de GC y se reclamarán si el objeto no tiene otra referencia fuerte).
Restaurante analogía
- Camarero - GC
- You - objeto en el montón
- Área / espacio del restaurante - espacio de pila
- Nuevo cliente - Nuevo objeto que quiere mesa en el restaurante.
Ahora, si usted es un cliente fuerte (análogo a una referencia fuerte), incluso si un cliente nuevo ingresa al restaurante o lo que sea, nunca abandonará su mesa (el área de memoria en el montón). El camarero no tiene derecho a decirle (o incluso solicitarle) que abandone el restaurante.
Si usted es un cliente blando (análogo a la referencia blanda), si un cliente nuevo ingresa al restaurante, el mesero no le pedirá que abandone la mesa a menos que no haya otra mesa vacía para acomodar al nuevo cliente. (En otras palabras, el camarero le pedirá que abandone la mesa solo si entra un nuevo cliente y no queda ninguna otra mesa para este nuevo cliente)
Si usted es un cliente débil (análogo a una referencia débil), el camarero, a su voluntad, puede (en cualquier momento) pedirle que abandone el restaurante: P
La única diferencia real entre una referencia suave y una referencia débil es que
el recolector de basura utiliza algoritmos para decidir si reclamar o no un objeto de fácil acceso, pero siempre reclama un objeto de difícil acceso.
Los seis tipos de estados de accesibilidad de objetos en Java:
- Objetos de fácil acceso: GC no recopilará ( reclamará la memoria ocupada por ) este tipo de objetos. Estos son accesibles a través de un nodo raíz u otro objeto muy accesible (es decir, a través de variables locales, variables de clase, variables de instancia, etc.)
- Objetos de fácil acceso: GC puede intentar recopilar este tipo de objetos dependiendo de la contención de la memoria. Estos son accesibles desde la raíz a través de uno o más objetos de referencia blandos.
- Objetos poco accesibles: GC debe recopilar este tipo de objetos. Estos son accesibles desde la raíz a través de uno o más objetos de referencia débiles
- Objetos resucitables : GC ya está en proceso de recopilar estos objetos. Pero pueden volver a uno de los estados: Fuerte / Suave / Débil por la ejecución de algún finalizador.
- Objeto accesible: el GC ya está en el proceso de recopilar estos objetos y ha determinado que no puede ser resucitado por ningún finalizador (si declara un método finalize (), entonces se habrá ejecutado su finalizador) . Estos son accesibles desde la raíz a través de uno o más objetos de referencia fantasma
- Objeto inalcanzable : un objeto no es fuerte, suave, débil, ni fantasma, y no puede resucitarse. Estos objetos están listos para su recuperación.
Para más detalles: https://www.artima.com/insidejvm/ed2/gc16.html «collapse
Referencias débiles se recogen con entusiasmo. Si GC encuentra que un objeto es débilmente accesible (accesible solo a través de referencias débiles), borrará las referencias débiles a ese objeto inmediatamente. Como tales, son buenos para mantener una referencia a un objeto para el cual su programa también mantiene (referenciada fuertemente) "información asociada" de alguna manera, como información de reflexión almacenada en caché sobre una clase, o una envoltura para un objeto, etc. Cualquier cosa que haga No tiene sentido mantenerlo después de que el objeto con el que está asociado es GC-ed. Cuando se borra la referencia débil, se pone en cola en una cola de referencia que su código sondea en algún lugar, y también descarta los objetos asociados. Es decir, mantiene información adicional sobre un objeto, pero esa información no es necesaria una vez que el objeto al que se refiere desaparece. En realidad, en ciertas situaciones puede incluso subclasificar WeakReference y mantener la información adicional asociada sobre el objeto en los campos de la subclase WeakReference. Otro uso típico de WeakReference es junto con Maps para mantener instancias canónicas.
SoftReferences, por otro lado, son buenos para almacenar en caché recursos externos y recreables, ya que el GC generalmente demora en borrarlos. Sin embargo, está garantizado que todas las referencias de software se borrarán antes de que se lance OutOfMemoryError, por lo que, en teoría, no pueden causar un OOME [*].
Un ejemplo típico de caso de uso es mantener una forma analizada de un contenido de un archivo. Implementaría un sistema en el que cargaría un archivo, lo analizaría y mantendría una SoftReference al objeto raíz de la representación analizada. La próxima vez que necesite el archivo, intentará recuperarlo a través de SoftReference. Si puede recuperarlo, se ahorrará otra carga / análisis, y si el GC lo borró mientras tanto, lo vuelve a cargar. De esa manera, utiliza la memoria libre para la optimización del rendimiento, pero no arriesga un OOME.
Ahora para el [*]. Mantener una SoftReference no puede causar un OOME en sí mismo. Si, por otro lado, utiliza SoftReference para una tarea, se debe usar una WeakReference (es decir, mantiene la información asociada con un Objeto de alguna manera fuertemente referenciada y la descarta cuando el objeto de Referencia se borra), puede encontrar OOME como su código que sondea la ReferenceQueue y descarta los objetos asociados podría no ejecutarse de manera oportuna.
Por lo tanto, la decisión depende del uso, si está almacenando información en caché que es costosa de construir, pero aún así es reconstruible a partir de otros datos, use referencias blandas, si mantiene una referencia a una instancia canónica de algunos datos, o si desea haga una referencia a un objeto sin "poseerlo" (evitando así que sea GC''d), use una referencia débil.
Se debe tener en cuenta que un objeto con una referencia débil solo se recogerá cuando SOLO tenga una (s) referencia (s) débil (s). Si tiene tanto como una referencia fuerte, no se recopila, no importa cuántas referencias débiles tenga.
SoftReference
está diseñado para cachés. Cuando se encuentra que una WeakReference
referencia a un objeto inalcanzable, se borrará de inmediato. SoftReference
se puede dejar como está. Por lo general, existe algún algoritmo relacionado con la cantidad de memoria libre y el último tiempo utilizado para determinar si se debe borrar. El algoritmo actual de Sun es borrar la referencia si no se ha utilizado en tantos segundos, ya que hay megabytes de memoria libre en el montón de Java (configurable, el servidor HotSpot comprueba el máximo montón posible establecido en -Xmx
). SoftReference
s se borrará antes de que se OutOfMemoryError
, a menos que se pueda OutOfMemoryError
a él.
En java Desde el más fuerte al más débil, hay: Fuerte, Suave, Débil y Fantasma.
Una referencia fuerte es una referencia normal que protege el objeto referido de la colección por GC. Es decir, nunca se recoge la basura.
Una referencia suave es elegible para la recolección por el recolector de basura, pero probablemente no será recolectada hasta que se necesite su memoria. es decir, la basura se acumula antes de OutOfMemoryError
.
Una referencia débil es una referencia que no protege un objeto referenciado de la recopilación por parte de GC. Es decir, la basura se acumula cuando no hay refs fuertes o suaves.
Una referencia fantasma es una referencia a un objeto a la que se hace referencia fantasma una vez finalizado, pero antes de que se haya reclamado su memoria asignada.
Analogía: Supongamos que una JVM es un reino, Object es un rey del reino y GC es un atacante del reino que intenta matar al rey (objeto).
- Cuando King es fuerte , GC no puede matarlo.
- Cuando King es suave , GC lo ataca, pero King gobierna el reino con protección hasta que haya recursos disponibles.
- Cuando King es Débil , GC lo ataca pero gobierna el reino sin protección.
- Cuando el rey es Fantasma , GC ya lo mató, pero el rey está disponible a través de su alma.
Referencia débil : los objetos que solo tienen una referencia débil se recolectan en cada ciclo de GC (menor o completo).
SoftReference : cuando los objetos a los que solo se hace referencia suave se recopilan, depende de:
-XX: SoftRefLRUPolicyMSPerMB = N flag (el valor predeterminado es 1000, también conocido como 1 segundo)
Cantidad de memoria libre en el montón.
Ejemplo:
- el montón tiene 10 MB de espacio libre (después de un GC completo);
- -XX: SoftRefLRUPolicyMSPerMB = 1000
Luego, el objeto al que solo se hace referencia con SoftReference se recopilará si la última vez que se accedió fue mayor a 10 segundos.
Referencia débil http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ref/WeakReference.html
Principio: weak reference
está relacionada con la recolección de basura. Normalmente, el objeto que tenga una o más reference
no será elegible para la recolección de basura.
El principio anterior no es aplicable cuando es weak reference
. Si un objeto solo tiene una referencia débil con otros objetos, entonces está listo para la recolección de basura.
Veamos el siguiente ejemplo: Tenemos un Map
con objetos donde Key es una referencia a un objeto.
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());
}
}
Ahora, durante la ejecución del programa hemos hecho emp = null
. El Map
contiene la clave no tiene sentido aquí ya que es null
. En la situación anterior, el objeto no es basura recolectada.
Mapa débil
WeakHashMap
es uno donde las entradas ( key-to-value mappings
) se eliminarán cuando ya no sea posible recuperarlas del Map
.
Déjame mostrar el mismo ejemplo anterior con 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());
}
}
Salida: Tomó 20 calls to System.gc()
para aMap size
de aMap size
de: 0.
WeakHashMap
solo tiene referencias débiles a las claves, no referencias fuertes como otras clases de Map
. Hay situaciones en las que hay que tener cuidado cuando se hace referencia al valor o la clave a pesar de haber utilizado WeakHashMap
. Esto puede evitarse envolviendo el objeto en una 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");
}
}
Referencias blandas.
Soft Reference
es ligeramente más fuerte que la referencia débil. La referencia suave permite la recolección de basura, pero le pide al recolector de basura que la elimine solo si no hay otra opción.
El recolector de basura no recolecta agresivamente objetos de fácil acceso como lo hace con los de difícil acceso, en vez de eso, solo recolecta objetos de fácil acceso si realmente "necesita" la memoria. Las referencias blandas son una forma de decirle al recolector de basura, "Mientras la memoria no sea muy apretada, me gustaría mantener este objeto cerca. Pero si la memoria se pone muy apretada, adelante, recógela y trataré con ese." Se requiere que el recolector de basura para borrar todas las referencias blandas antes de que pueda lanzar OutOfMemoryError
.