¿Cuál es la diferencia entre SoftReference y WeakReference en Java?

¿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 cualquier parte del código, puede usar weakWidget.get() para obtener el objeto del Widget 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 sólidas al widget) que weakWidget.get() repente comience a devolver null .

Referencias suaves

Una referencia suave es exactamente como una referencia débil, excepto que está menos ansioso por tirar el objeto al que se refiere. Un objeto que solo es débilmente alcanzable (las referencias más fuertes a él son WeakReferences ) se descartarán en el siguiente ciclo de recolección de elementos no utilizados, pero un objeto que se puede alcanzar suavemente generalmente se mantendrá durante un tiempo.

SoftReferences se requiere que SoftReferences se comporte de forma diferente que WeakReferences , pero en la práctica los objetos de scope suave generalmente se conservan siempre que la memoria sea abundante. Esto los convierte en una excelente base para un caché, como la memoria caché de imágenes descrita anteriormente, ya que puede dejar que el recolector de basura se preocupe por la accesibilidad de los objetos (un objeto de gran scope nunca se eliminará del caché) y lo mal que sea necesita la memoria que están consumiendo.

Y Peter Kessler agregó en un comentario:

Sun JRE trata las SoftReferences de forma diferente a las WeakReferences. Intentamos aferrarnos al objeto al que hace referencia SoftReference si no hay presión sobre la memoria disponible. Un detalle: la política para los JRE “-client” y “-server” es diferente: el JRE del cliente intenta mantener su huella pequeña al preferir borrar SoftReferences en lugar de expandir el heap, 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 recogen con entusiasmo. Si GC encuentra que un objeto es débilmente alcanzable (accesible solo a través de referencias débiles), borrará las referencias débiles de ese objeto inmediatamente. Como tales, son buenos para mantener una referencia a un objeto para el cual su progtwig también conserva (fuertemente referenciado) “información asociada”, como la información de reflexión en caché sobre una clase o un contenedor para un objeto, etc. Cualquier cosa que haga no tiene sentido quedarse después de que el objeto al que está asociado esté 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, incluso puede subclasificar WeakReference y conservar 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 el almacenamiento en caché de recursos externos y recreables, ya que el GC por lo general demora su limpieza. Sin embargo, está garantizado que todas las SoftReferences se borrarán antes de que se genere OutOfMemoryError, por lo que teóricamente no pueden causar un OOME [*].

El ejemplo típico de caso de uso 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 referencia suave 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 esta forma, utiliza la memoria libre para la optimización del rendimiento, pero no arriesgue un OOME.

Ahora para el [*]. Mantener una SoftReference no puede causar un OOME en sí mismo. Si, por otro lado, utilizas por error SoftReference para una tarea que WeakReference está destinada a ser utilizada (es decir, mantienes la información asociada a un Objeto fuertemente referenciada y la descartas cuando se borra el objeto Reference), puedes ejecutar a 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 en caché información que es costosa de construir, pero no obstante reconstruible a partir de otros datos, use referencias suaves, si está manteniendo una referencia a una instancia canónica de algunos datos, o si desea tener una referencia a un objeto sin “poseerlo” (evitando así que sea GC’d), use una referencia débil.

En Java ; ordena 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 recostackción por GC. es decir, nunca se acumula basura.

Una referencia de software es elegible para la recolección por el recolector de elementos no utilizados, pero probablemente no se recopile 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 colección por GC. es decir, la basura se acumula cuando no hay referencias fuertes o suaves.

Una referencia Phantom es una referencia a un objeto que se hace referencia fantasma después de que se ha finalizado, pero antes de recuperar su memoria asignada.

Fuente

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 blando , 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 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 tiene solo una referencia débil con otros objetos, entonces está listo para la recolección de basura.

Miremos el siguiente ejemplo: Tenemos un Map con Objetos donde la Clave es referencia de un objeto.

 import java.util.HashMap; public class Test { public static void main(String args[]) { HashMap aMap = new HashMap(); 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 progtwig 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.

WeakHashMap

WeakHashMap es uno en el que las entradas ( key-to-value mappings ) se eliminarán cuando ya no sea posible recuperarlas del Map .

Déjame mostrar el ejemplo anterior igual con WeakHashMap

 import java.util.WeakHashMap; public class Test { public static void main(String args[]) { WeakHashMap aMap = new WeakHashMap(); 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 dar como resultado aMap size de aMap size de: 0.

WeakHashMap tiene solo referencias débiles a las claves, no a referencias fuertes como otras clases de Map . Hay situaciones que debe tener en cuenta cuando se hace referencia al valor o la clave aunque haya usado 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 map = new HashMap(); WeakReference> aMap = new WeakReference>( 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 un poco 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 recoge de manera agresiva los objetos de acceso suave de la misma manera que lo hace con los de acceso débil; en su lugar, solo recoge objetos de acceso suave 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. Pero si la memoria se pone realmente apretada, adelante y recójala y yo trataré con ese.” Se requiere que el recolector de basura borre todas las referencias OutOfMemoryError antes de que pueda arrojar OutOfMemoryError .

La única diferencia real entre una referencia suave y una referencia débil es que el recolector de basura uses algorithms to decide whether or not to reclaim a softly reachable object, but always reclaims a weakly reachable object.

SoftReference está diseñado para cachés. Cuando se encuentra que una WeakReference referencia a un objeto inalcanzable, se borrará inmediatamente. SoftReference puede dejarse como está. Por lo general, hay algún algoritmo relacionado con la cantidad de memoria libre y la última vez que se usó para determinar si debe borrarse. El algoritmo de Sun actual es borrar la referencia si no se ha utilizado en tantos segundos como hay megabytes de memoria libre en el montón de Java (configurables, HotSpot del servidor comprueba contra el montón máximo posible tal como lo establece -Xmx ). SoftReference s se borrará antes de OutOfMemoryError , a menos que se pueda OutOfMemoryError a él.

La única diferencia real

Según el documento , las WeakReferences sueltas deben borrarse con un GC en ejecución.

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. Los cachés sensibles a la memoria usan SoftReferences, no WeakReferences.


El único uso adecuado de WeakReference es observar la ejecución de GC. Para ello, cree una nueva WeakReference cuyo objeto se salga inmediatamente del scope, luego intente obtener nulo de weak_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 pésimo truco para implementar softreference de prioridad 2, de modo que no tenga que escribir uno, pero no funciona como se esperaba porque el caché se borrará en cada ejecución del GC, incluso cuando hay memoria libre. Ver https://stackoverflow.com/a/3243242/632951 para los phails. (Además, ¿qué pasa si necesitas más de 2 niveles de prioridad de caché? Aún necesitarías una biblioteca real para ello).

  • un pésimo truco para asociar datos con un objeto de una clase existente, pero crea una fuga de memoria (OutOfMemoryError) cuando su GC decide tomarse un descanso después de crear sus débiles referencias. Además, está más allá de lo feo: un mejor enfoque es usar tuplas.

  • un pirateo pésimo para asociar datos con un objeto de una clase existente, donde la clase tiene el valor de hacerse no subclassable, 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 subclassable, o editar la función y hacer que tome una interfaz en lugar de una clase, o use una función alternativa.

Los seis tipos de estados de accesibilidad de objetos en Java –

  1. Objetos muy alcanzables: el GC no recogerá ( recuperará la memoria ocupada por ) este tipo de objetos. Estos son accesibles a través de un nodo raíz u otro objeto fuertemente accesible (es decir, a través de variables locales, variables de clase, variables de instancia, etc.)
  2. Objetos accesibles lentamente: GC puede intentar recolectar 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 suave
  3. Objetos poco alcanzables: GC debe recolectar este tipo de objetos. Estos son accesibles desde la raíz a través de uno o más objetos de referencia débiles
  4. Objetos resucitables : GC ya está en el proceso de recostackción de estos objetos. Pero pueden volver a uno de los estados: Fuerte / Suave / Débil por la ejecución de algún finalizador
  5. Objeto accesible Phantom ly – GC ya está en proceso de recostackción de estos objetos y ha determinado que no será resucitado por ningún finalizador (si declara un método finalize () en sí mismo, 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
  6. Objeto inaccesible : un objeto no es fuerte, débil, débil ni alcanzable por el espectro, y no es resucitado. Estos objetos están listos para la recuperación

Para más detalles: https://www.artima.com/insidejvm/ed2/gc16.html «collapse

Débil referencia

Cuando hay una o más referencias a un objeto, no será basura recogida en Java. Pero esta regla depende del tipo de referencia que sea. Si un objeto tiene solo una referencia débil asociada con otros objetos, entonces es un candidato válido para la recolección de basura.

Tomemos un escenario de muestra para entenderlo mejor. Deje que TextView sea un objeto (recientemente, progtwigndo en Android y utilizando su clase, por ejemplo :-)) y tendremos identificadores generados por el progtwig para su identificación. Estos identificadores se utilizan en otros objetos para hacer referencia a TextViews.

 ... Map textViewIdMap = new HashMap(); textViewIdMap.put(textView1, iD1); textViewIdMap.put(textView2, iD2) ... 

la clave es el objeto TextView y el valor es Id. Ahora, durante la ejecución del progtwig, hemos eliminado un objeto TextView, digamos textView1. No requerimos ese objeto de vista, por lo que lo hemos hecho nulo. Ahora, ¿qué pasará con el par clave-valor (textView1, iD1) almacenado en HashMap? Este par a partir de ahora no tiene sentido y no es necesario ya que la propia vista de texto es nula.

Por lo tanto, programática debemos asegurarnos de que, cuando se elimina una vista de texto, se elimine su entrada correspondiente en el mapa. Solo entonces, ese objeto se convierte en candidato para la recolección de basura. De lo contrario, aunque no se use en tiempo de ejecución, este obsoleto no se recogerá.

Referencia suave

La referencia suave es un poco 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. Es decir, es elegible para la recolección de elementos no utilizados, pero el recolector de elementos no utilizados puede eliminarlo en función de la escasez de memoria que tenga. Si se deja con poca memoria y está en posición de reclamar memoria, entonces recogerá las referencias suaves.

Este artículo puede ser muy útil para entender referencias fuertes, suaves, débiles y fantasmas.


Para darte un resumen,

Si solo tiene referencias débiles a un objeto (sin referencias fuertes), el GC reclamará el objeto en el siguiente ciclo de GC.

Si solo tiene referencias suaves a un objeto (sin referencias fuertes), el objeto será reclamado por GC solo cuando JVM se quede sin memoria.


Así que puedes decir que las referencias fuertes tienen la máxima potencia (nunca pueden ser recolectadas por GC)

Las referencias suaves son poderosas que las referencias débiles (ya que pueden escapar del ciclo de GC hasta que JVM se quede sin memoria)

Las referencias débiles son incluso menos poderosas que las referencias suaves (ya que no pueden salir de ningún ciclo de GC y se recuperarán si el objeto no tiene otra referencia fuerte).


Restaurante Analogy

  • Camarero – GC
  • Tú – Objeto en montón
  • Área / espacio del restaurante – Espacio de montón
  • Nuevo cliente: nuevo objeto que quiere mesa en el restaurante

Ahora bien, si usted es un cliente fuerte (análogo a una referencia fuerte), incluso si llega un nuevo cliente en el restaurante o lo que siempre le apetezca, nunca abandonará su mesa (el área de memoria en el montón). El camarero no tiene derecho a decirle (o incluso a pedirle) que salga del restaurante.

Si es un cliente blando (análogo al de referencia), si un nuevo cliente entra al restaurante, el mesero no le pedirá que se vaya de la mesa, a menos que no haya otra mesa vacía para acomodar al nuevo cliente. (En otras palabras, el mesero le pedirá que abandone la mesa solo si ingresa un nuevo cliente y no le queda otra mesa para este nuevo cliente)

Si usted es un cliente débil (análogo a una referencia débil), entonces el mesero, a su antojo, puede (en cualquier momento) pedirle que salga del restaurante: P

Se debe tener en cuenta que un objeto débilmente referenciado solo se recostackrá cuando tenga SÓLO referencia (s) débil (s). Si tiene una referencia fuerte, no se recostack, no importa cuántas referencias débiles tenga.

WeakReference : los objetos a los que solo se hace referencia de forma débil se recostackn en cada ciclo de GC (menor o total).

SoftReference : cuando los objetos que solo se referencian de forma suave se recostackn depende de:

  1. -XX: SoftRefLRUPolicyMSPerMB = N flag (el valor predeterminado es 1000, también conocido como 1 segundo)

  2. Cantidad de memoria libre en el montón.

    Ejemplo:

    • montón tiene 10 MB de espacio libre (después de GC completo);
    • -XX: SoftRefLRUPolicyMSPerMB = 1000

    A continuación, el objeto al que SoftReference hace referencia se recostackrá si la última vez que se accedió es superior a 10 segundos.