¿Cuál es la diferencia entre java.lang.ref.WeakReference
y java.lang.ref.SoftReference
?
¿Cuál es la diferencia entre java.lang.ref.WeakReference
y java.lang.ref.SoftReference
?
Respuestas:
De Comprender las referencias débiles , de Ethan Nicholas:
Referencias débiles
Una referencia débil , simplemente, 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. Crea una referencia débil como esta:
WeakReference weakWidget = new WeakReference(widget);
y luego en otra parte del código que puede usar
weakWidget.get()
para obtener elWidget
objeto real . Por supuesto, la referencia débil no es lo suficientemente fuerte como para evitar la recolección de basura, por lo que puede encontrar (si no hay referencias fuertes al widget) que deweakWidget.get()
repente comienza a regresarnull
....
Referencias suaves
UNA referencia suave es exactamente como una referencia débil, excepto que está menos ansiosa por tirar el objeto al que se refiere. Un objeto al que solo se puede llegar débilmente (las referencias más fuertes a él
WeakReferences
) se descartarán en el próximo ciclo de recolección de basura, pero un objeto al que se puede acceder suavemente generalmente se quedará por un tiempo.
SoftReferences
no están obligados a comportarse de manera diferente aWeakReferences
, pero en la práctica, los objetos de alcance suave generalmente se retienen siempre que la memoria sea abundante. Esto los convierte en una base excelente para un caché, como el caché de imágenes descrito anteriormente, ya que puede dejar que el recolector de basura se preocupe tanto por lo accesible que son los objetos (un objeto fuertemente accesible nunca se eliminará del caché) y lo mal que necesita la memoria que están consumiendo.
Y Peter Kessler agregó en un comentario:
Sun JRE trata las SoftReferences de manera diferente a WeakReferences. 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 "-client" y "-server" es diferente: el JRE -client intenta mantener su huella pequeña prefiriendo borrar SoftReferences en lugar de expandir el montón, mientras que el JRE -server intenta mantener su alto rendimiento al preferir expandir el montón (si es posible) en lugar de borrar SoftReferences. Una talla no sirve para todos.
Las referencias débiles se recopilan 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 tal, son buenos para mantener una referencia a un objeto para el cual su programa también guarda (fuertemente referenciada) "información asociada" en algún momento, como información de reflexión en caché sobre una clase, o un contenedor para un objeto, etc. Cualquier cosa que haga no tiene sentido guardarlo después de que el objeto al que está asociado sea GC-ed. Cuando la referencia débil se borra, 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 hace referencia desaparece. Realmente, en ciertas situaciones, incluso puede 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 en conjunción 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, se garantiza que todas las SoftReferences se borrarán antes de que se arroje OutOfMemoryError, por lo que en teoría no pueden causar un OOME [*].
Un ejemplo de caso de uso típico es mantener una forma analizada de un contenido de un archivo. Implementaría un sistema donde 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 ahorró otra carga / análisis, y si el GC lo borró mientras tanto, lo vuelve a cargar. De esa manera, utiliza memoria libre para la optimización del rendimiento, pero no se arriesga a un OOME.
Ahora para el [*]. Mantener una SoftReference no puede causar un OOME en sí mismo. Si, por otro lado, utiliza por error SoftReference para una tarea, se debe utilizar una WeakReference (es decir, si mantiene la información asociada a un Objeto fuertemente referenciada y la descarta cuando el objeto de Referencia se borra), puede ejecutar OOME como su código que sondea el 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 en caché información que es costosa de construir, pero no obstante reconstruible a partir de otros datos, use referencias suaves, si mantiene una referencia a una instancia canónica de algunos datos, o si desea tenga una referencia a un objeto sin "poseerlo" (evitando así que sea GC'd), use una referencia débil.
WeakReference
es que en los lugares donde uno debería usarlo, el hecho de que uno pueda permanecer válido durante un tiempo después de que la referencia salga del alcance puede ser tolerable, pero no es deseable.
WeakReference
cual es observar las ejecuciones de GC. Ver elaboración: stackoverflow.com/a/46291143/632951
En java ; orden de más fuerte a 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 acumula basura.
Una referencia suave es elegible para la recolección por parte del recolector de basura, pero probablemente no se recolectará hasta que se necesite su memoria. es decir, la basura se acumula antes OutOfMemoryError
.
Una referencia débil es una referencia que no protege un objeto referenciado de la colección por GC. es decir, la basura se acumula cuando no hay referencias fuertes o suaves.
Una referencia fantasma es una referencia a un objeto al que se hace referencia fantasma una vez que se ha finalizado, pero antes de que se haya recuperado su memoria asignada.
Analogía: suponga 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).
until memory is available
no tiene sentido. Qué quiere decir is eligible for collection by garbage collector, but probably won't be collected until its memory is needed for another use
?
Referencia débil http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ref/WeakReference.html
Principio: weak reference
está relacionado con la recolección de basura. Normalmente, los objetos que tienen uno o más reference
no serán elegibles para la recolección de basura.
El principio anterior no es aplicable cuando lo 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 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 que hemos realizado emp = null
. Mantener Map
presionada la tecla no tiene sentido aquí tal como es null
. En la situación anterior, el objeto no es basura recolectada.
WeakHashMap
WeakHashMap
es uno donde las entradas ( key-to-value mappings
) se eliminarán cuando ya no sea posible recuperarlas del Map
.
Permítanme 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()
como resultado en aMap size
: 0.
WeakHashMap
solo tiene referencias débiles a las teclas, no referencias fuertes como otras Map
clases. Hay situaciones que debe tener cuidado cuando el valor o la clave están fuertemente referenciados a pesar de haberlo utilizado WeakHashMap
. Esto se puede evitar 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 suaves
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 limpie solo si no hay otra opción.
El recolector de basura no recolecta de manera agresiva los objetos que se pueden alcanzar suavemente como lo hace con los que se pueden alcanzar débilmente; en cambio, solo recolecta los objetos que se pueden alcanzar suavemente si realmente "necesita" la memoria. Las referencias suaves son una forma de decirle al recolector de basura: "Mientras la memoria no sea demasiado apretada, me gustaría mantener este objeto cerca. Pero si la memoria se pone muy apretada, adelante, recójala y me ocuparé con ese." Se requiere que el recolector de basura borre todas las referencias suaves antes de poder lanzar OutOfMemoryError
.
NullPointerException
en aMap.get().put(...)
.
WeakHashMap
ejemplo (ya que es el primero que demuestra un comportamiento Débil). Vistazo a doc para "WeakHashMap": "An entry in a WeakHashMap will automatically be removed when its key is no longer in ordinary use. "
El punto de usar WeakHashMap todo es que usted no tiene que declarar / de acceso en un WeakReference; WeakHashMap lo hace internamente. docs.oracle.com/javase/7/docs/api/java/util/WeakHashMap.html
WeakHashMap
en acción, con la aplicación de ejemplo que muestra cómo se eliminan las entradas solo después de que se ejecuta la recolección de basura, consulte mi Respuesta a la pregunta, ¿WeakHashMap está creciendo constantemente o borra las claves de basura? .
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 accesible de manera suave, pero siempre reclama un objeto débilmente accesible.
SoftReference
Está diseñado para cachés. Cuando se descubre que un objeto hace WeakReference
referencia a un objeto inalcanzable, se borrará de inmediato. SoftReference
puede dejarse como está. Por lo general, hay 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 como haya megabytes de memoria libre en el almacenamiento dinámico de Java (configurable, el HotSpot del servidor verifica con el almacenamiento dinámico máximo establecido por -Xmx
). SoftReference
s se borrará antes de que OutOfMemoryError
se lance, a menos que se pueda acceder de otra manera.
java.lang
. Tal abuso de sinónimos no le está haciendo ningún bien a nadie.
Este artículo puede ser muy útil para comprender referencias fuertes, suaves, débiles y fantasmas.
Para darle un resumen,
Si solo tienes referencias débiles a un objeto (sin referencias fuertes), entonces el objeto será reclamado por GC en el próximo ciclo de GC.
Si solo tiene referencias suaves a un objeto (sin referencias fuertes), entonces el objeto será reclamado por GC solo cuando JVM se quede sin memoria.
Entonces puedes decir que las referencias fuertes tienen el poder supremo (nunca puede ser recolectado por GC)
Las referencias suaves son poderosas que las débiles (ya que pueden escapar del ciclo de GC hasta que JVM se quede sin memoria)
Las referencias débiles son incluso menos potentes que las referencias suaves (ya que no pueden escapar de ningún ciclo de GC y se recuperarán si el objeto no tiene otra referencia fuerte).
Analogía de restaurantes
Ahora, si usted es un cliente fuerte (análogo a una referencia fuerte), incluso si un nuevo cliente entra en el restaurante o lo que sea que sea feliz, nunca dejará su mesa (el área de memoria en el montón). El camarero no tiene derecho a decirle (o incluso pedirle) que abandone el restaurante.
Si eres un cliente suave (análogo a una referencia flexible), si un cliente nuevo entra al restaurante, el camarero no le pedirá que abandone la mesa a menos que no quede otra mesa vacía para acomodar al nuevo cliente. (En otras palabras, el camarero le pedirá que abandone la mesa solo si un nuevo cliente interviene y no queda 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 salga del restaurante: P
Según el documento , un GC en ejecución debe eliminar las referencias débiles sueltas .
Según el documento , las SoftReferences sueltas deben borrarse antes de lanzar OOM.
Esa es la única diferencia real. Todo lo demás no es parte del contrato. (Asumiré que los últimos documentos son contractuales).
SoftReferences son útiles. Las memorias caché sensibles a la memoria usan SoftReferences, no WeakReferences.
weak_ref.get()
. Cuando es así null
, aprende que entre esta duración, el GC se ejecutó.
En cuanto al uso incorrecto de WeakReference, la lista es interminable:
un truco pésimo para implementar la softreferencia de prioridad 2 de modo que no tenga que escribir una, pero no funciona como se esperaba porque la memoria caché se borrará en cada ejecución del GC, incluso cuando haya memoria de sobra. Consulte https://stackoverflow.com/a/3243242/632951 para ver las copias. (Además, ¿qué pasa si necesita más de 2 niveles de prioridad de caché? Aún necesitaría una biblioteca real para ello).
un pésimo truco para asociar datos con un objeto de una clase existente, pero crea una pérdida de memoria (OutOfMemoryError) cuando su GC decide tomarse un descanso después de crear sus referencias débiles. Además, es más que feo: un mejor enfoque es usar tuplas.
un pésimo truco para asociar datos con un objeto de una clase existente, donde la clase tiene el descaro de no poder subclasearse, y se usa en un código de función existente al que debe llamar. En tal caso, la solución adecuada es editar la clase y hacer que sea subclase, o editar la función y hacer que tome una interfaz en lugar de una clase, o use una función alternativa.
equals()
es solo identidad de objeto? Las referencias suaves parecen un desperdicio allí, porque una vez que un objeto clave ya no es fácilmente accesible, nadie volverá a buscar esa asignación nuevamente.
Los seis tipos de estados de accesibilidad de objetos en Java:
Para más detalles: https://www.artima.com/insidejvm/ed2/gc16.html «collapse
Se debe tener en cuenta que un objeto débilmente referenciado solo se recopilará cuando SOLO tenga referencias débiles. Si tiene tanto como una referencia fuerte, no se recopilará sin importar cuántas referencias débiles tenga.
Para dar un aspecto de uso de memoria en acción, realicé un experimento con referencias Strong, Soft, Weak & Phantom bajo carga pesada con objetos pesados al retenerlos hasta el final del programa. Luego monitoreó el uso del montón y el comportamiento del GC . Estas métricas pueden variar caso por caso, pero seguramente brindan una comprensión de alto nivel. A continuación se encuentran los hallazgos.
Comportamiento de montón y GC bajo carga pesada
Puede obtener gráficos más detallados , estadísticas, observaciones para este experimento aquí .
WeakReference : los objetos a los que solo se hace referencia débilmente se recopilan en cada ciclo de GC (menor o completo).
SoftReference : cuando los objetos a los que solo se hace una 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:
Luego, el objeto al que hace referencia SoftReference solo se recopilará si la última vez que se accedió es mayor de 10 segundos.