Java: diferencia entre referencia fuerte / suave / débil / fantasma

179

He leído este artículo sobre el tema, pero realmente no lo entiendo. Por favor, dame algunos consejos junto con ejemplos al describir los conceptos.

Matthias Braun
fuente
44
He leído ese documento, no me ayuda a imaginar qué diferencia. (tal vez porque es un documento de lectura dura)
14
Si lees ese artículo y aún no lo entiendes, ¿tienes preguntas específicas al respecto? Es difícil responder a "explícame Foo", "esto es lo que significa", "no lo entiendo" sin detalles sobre qué partes no obtienes.
yshavit
@LouisWasserman El enlace superior ya no es válido.
Mehraj Malik, el

Respuestas:

142

Java proporciona dos tipos / clases diferentes de objetos de referencia : fuertes y débiles . Los objetos de referencia débiles se pueden dividir en soft y phantom .

  • Fuerte
  • Débiles
    • suave
    • fantasma

Vamos punto por punto.

Objeto de referencia fuerte

StringBuilder builder = new StringBuilder();

Este es el tipo / clase predeterminado del Objeto de referencia, si no se especifica de manera diferente: builderes un Objeto de referencia fuerte. Este tipo de referencia hace que el objeto referenciado no sea elegible para GC. Es decir, cuando un objeto es referenciado por un cadena de objetos de referencia fuertes hace referencia a , no se puede recolectar basura.

Objeto de referencia débil

WeakReference<StringBuilder> weakBuilder = new WeakReference<StringBuilder>(builder);

Los Objetos de referencia débiles no son el tipo / clase predeterminado de Objeto de referencia y, para ser utilizados, deben especificarse explícitamente como en el ejemplo anterior. Este tipo de referencia hace que el objeto de referencia sea elegible para GC. Es decir, en caso de que la única referencia alcanzable para elStringBuilder objeto en la memoria sea, en realidad, la referencia débil, entonces el GC puede recolectar basuraStringBuilder objeto. Cuando un objeto en memoria es accesible solo por Objetos de referencia débiles, se convierte automáticamente elegible para GC.

Niveles de debilidad

Se pueden alistar dos niveles diferentes de debilidad: suave y fantasma .

Un suave objeto de referencia es básicamente un objeto de referencia débil que permanece un poco más en la memoria: normalmente, resiste el ciclo de GC hasta que no hay memoria disponible y existe el riesgo deOutOfMemoryError (en ese caso, se puede eliminar).

Por otro lado, un Objeto de referencia fantasma es útil solo para saber exactamente cuándo un objeto se ha eliminado efectivamente de la memoria: normalmente se utilizan para corregir el comportamiento extraño de reactivación / resurrección finalize () , ya que en realidad no devuelven el objeto en sí, sino solo ayuda en el seguimiento de su presencia en la memoria .

Los objetos de referencia débiles son ideales para implementar módulos de caché. De hecho, se puede implementar una especie de desalojo automático al permitir que el GC limpie las áreas de memoria siempre que los objetos / valores ya no sean accesibles mediante una fuerte cadena de referencias. Un ejemplo es el WeakHashMap que retiene claves débiles.

Paolo Maresca
fuente
76

Referencia débil:

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.

Referencia suave:

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 son WeakReferences) se descartará 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.

Referencia fantasma:

Una referencia fantasma es bastante diferente de SoftReference o WeakReference. Su agarre sobre su objeto es tan tenue que ni siquiera puede recuperar el objeto; su método get () siempre devuelve nulo. El único uso para dicha referencia es realizar un seguimiento de cuándo se pone en cola en un ReferenceQueue, ya que en ese momento sabe que el objeto al que apunta está muerto.

Este texto fue extraído de: https://weblogs.java.net/blog/2006/05/04/understanding-weak-references

Punith Raj
fuente
1
Si bien todo en esta respuesta parece correcto, también me parece que puede haber un error en la página web vinculada. El Javadoc para el paquete java.lang.ref y para PhantomReference sugieren que un objeto no se recolecta basura hasta después de que ya no es "fantasma accesible", lo que implica que (a diferencia de SoftReference) una PhantomReference debe ser eliminada antes de que el objeto al que se refiere pueda ser basura recolectada ... y su puesta en cola no indica que se haya liberado la memoria asociada.
Theodore Murdock
2
Para el registro, preferiría vivir en un mundo donde esa publicación de blog es correcta.
Theodore Murdock
1
@TheodoreMurdock El javadoc es correcto. Una referencia fantasma no impide en absoluto la recolección de basura. Una vez que un objeto está en cola, no puede ser guardado ni siquiera por un finalizador, ya que los finalizadores ya se han ejecutado. Está muerto, pero aún no se ha ido.
Leliel
@Leliel En realidad, una referencia fantasma hace en la recolección de basura impiden hecho después de que se pone en cola ... Me di cuenta de esto recientemente cuando un insecto causó un hilo de limpieza a la salida temprana. La existencia de referencias fantasmas fue suficiente para garantizar que cada objeto referenciado fantasma se conservara en mi volcado de almacenamiento dinámico, no disponible para la recopilación ... si no procesa la cola o no hace que la referencia fantasma sea elegible para gc al procesar la cola ( y no borre () la referencia fantasma), entonces su pérdida de memoria incluirá tanto la referencia fantasma como el objeto referenciado.
Theodore Murdock
25

La diferencia simple entre SoftReferencey WeakReferencees proporcionada por el desarrollador de Android .

La diferencia entre ay SoftReferencea WeakReferencees el momento en el que se toma la decisión de aclarar y poner en cola la referencia:

  • A se SoftReferencedebe borrar y poner en cola lo más tarde posible, es decir, en caso de que la VM esté en peligro de quedarse sin memoria.

  • A WeakReferencese puede borrar y poner en cola tan pronto como se sepa que tiene una referencia débil.

Muhammad Nabeel Arif
fuente
16

Los tres términos que ha utilizado se relacionan principalmente con la elegibilidad de Object para recolectar basura.

Referencia débil :: Es una referencia que no es lo suficientemente fuerte como para obligar al objeto a permanecer en la memoria. Es el capricho de coleccionista de basura para recoger ese objeto para la recolección de basura. No puede obligar a ese GC a no recogerlo .

Referencia suave :: Es más o menos igual que la referencia débil. Pero puede decir que mantiene el objeto un poco más fuerte que la referencia débil de la recolección de basura.

Si los recolectores de basura recopilan la referencia débil en el primer ciclo de vida, la recopilación de la referencia flexible se realizará en el siguiente ciclo de recolección de basura.

Referencia fuerte :: Es justo opuesto a los dos tipos de referencias anteriores. Son menos propensos a que se recolecte basura (en su mayoría, nunca se recolectan).

Puede consultar el siguiente enlace para obtener más información:

http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/ref/Reference.html

Sabya
fuente
3
Creo que esto está mal: "Si los recolectores de basura recolectan la referencia débil en el primer ciclo de vida, recolectarán la referencia flexible en el próximo ciclo de recolección de basura". No es necesariamente así, ¿cómo puede estar tan seguro de que ocurren en una ejecución consecutiva de GC? GC puede permitir que los objetos con referencias suaves vivan incluso en la segunda ejecución y la tercera ejecución también. No hay documentación para ello, si es así, por favor mencione el enlace que especifica.
Saurabh Patil
2
Además, su respuesta es un poco vaga, mire esta oración 'Es más o menos igual que la referencia débil. Pero se puede decir que contiene el objeto un poco más fuerte que la referencia débil de la recolección de basura. - claramente pregunta sobre la diferencia y no las similitudes, todas estas palabras agregan más confusión que claridad al tema.
Saurabh Patil
@SaurabhPatil - Perdí tu comentario. Aquí van las respuestas. 1. "claramente pregunta por la diferencia y no por las similitudes" - Consulte la descripción de la pregunta (no "solo" el título) "Por favor, dame un consejo y dame un ejemplo para describir". 2. "Pero se puede decir que contiene el objeto un poco más ..." Creo que SOF ofrece la opción de votar a favor y dar nuevas respuestas también.
Sabya
14

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


Para darle un resumen,

Si tiene una referencia fuerte a un objeto, GC (Recolector de basura) nunca podrá recolectar / reclamar el objeto.

Si solo tiene 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.

Creamos referencias fantasmas a un objeto para realizar un seguimiento de cuándo el objeto se pone en cola en el ReferenceQueue. Una vez que sepa que puede realizar una finalización detallada. (Esto te salvaría de resucitar accidentalmente el objeto ya que la referencia fantasma no te da el referente). Le sugiero que lea este artículo para obtener detalles detallados sobre esto.


Entonces puedes decir que, las referencias fuertes tienen el máximo poder (nunca puede ser recolectado 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 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

  • Camarero - GC
  • Usted - Objeto en el montón
  • Área / espacio del restaurante: espacio de almacenamiento dinámico
  • Nuevo cliente - Nuevo objeto que quiere mesa en restaurante

Ahora si eres 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 usted es un cliente flexible (análogo a una referencia flexible), si un nuevo cliente 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), entonces el camarero, a su voluntad, puede (en cualquier momento) pedirle que salga del restaurante: P

La lujosa Kothari
fuente
10

4 grados de referencia Strong, Weak, Soft, Phantom

Fuerte: es un tipo de referencia que hace que el objeto referenciado no sea elegible para GC. Clases de constructor. por ejemplo, StringBuilder

Débil: es una referencia elegible para GC.

Soft: es un tipo de referencia cuyo objeto es elegible para GC hasta que la memoria esté disponible. Lo mejor para el caché de imágenes. Los retendrá hasta que la memoria esté disponible.

Fantasma: es un tipo de referencia cuyo objeto es directamente elegible para GC. Solo se usa para saber cuándo se elimina un objeto de la memoria.

usos:

  1. Le permite identificar cuándo un objeto se elimina exactamente de la memoria.

  2. cuando el finalize()método está sobrecargado, es posible que GC no suceda de manera oportuna para los objetos elegibles para GC de las dos clases. Entonces, la referencia fantasma los hace elegibles para GC antes finalize(), es por eso que puede obtener OutOfMemoryErrors incluso cuando la mayor parte del montón es basura.

Las referencias débiles son ideales para implementar los módulos de caché.

Preetham RU
fuente
10

Referencias fuertes

Estas son sus referencias de objetos regulares que codificamos diariamente:

Employee emp = new Employee();

La variable "emp" contiene una referencia fuerte a un objeto Empleado y los objetos a los que se puede acceder a través de cualquier cadena de referencias fuertes no son elegibles para la recolección de basura. Por lo general, esto es lo que quieres pero no siempre. Ahora supongamos que estamos obteniendo muchos empleados de la base de datos en una colección o mapa, y necesitamos procesar mucho en ellos regularmente, por lo tanto, para mantener el rendimiento, los mantendremos en el caché.

En la medida en que esto sea bueno, pero ahora necesitamos datos diferentes y no necesitamos esos objetos Empleado y no se hace referencia a ellos desde ninguna parte, excepto el caché. ¿Qué está causando una pérdida de memoria porque estos objetos no están en uso pero aún no son elegibles para la recolección de basura y no podemos eliminar esos objetos del caché porque no tenemos referencia a ellos? Entonces, aquí o necesitamos vaciar todo el caché manualmente, lo cual es tedioso o podríamos usar otras referencias amables, por ejemplo, Referencias débiles.

Referencias débiles

Una referencia débil no fija un objeto en la memoria y será GC'd en el próximo ciclo de GC si no se hace referencia desde otras referencias. Podemos usar la clase WeakReference que proporciona Java para crear los tipos de cachés anteriores, que no almacenarán objetos a los que no se haga referencia desde otro lugar.

WeakReference<Cache> cache = new WeakReference<Cache>(data);

Para acceder a los datos, debe llamar a cache.get (). Esta llamada a get puede devolver nulo si la referencia débil era recolección de basura: debe verificar el valor devuelto para evitar NPE. Java proporciona colecciones que usan referencias débiles, por ejemplo, la clase WeakHashMap almacena claves (no valores) como referencias débiles. Si la clave es GC'd, el valor también se eliminará automáticamente del mapa.

Dado que las referencias débiles también son objetos, necesitamos una forma de limpiarlas (ya no son útiles cuando el objeto al que estaban haciendo referencia ha sido GC'd). Si pasa un ReferenceQueue al constructor para una referencia débil, entonces el recolector de basura agregará esa referencia débil al ReferenceQueue antes de que finalicen o GC'd. Puede procesar periódicamente esta cola y lidiar con referencias muertas.

Referencias suaves

Una SoftReference es como una WeakReference pero es menos probable que se recolecte basura. Las referencias suaves se borran a discreción del recolector de basura en respuesta a la demanda de memoria. La máquina virtual garantiza que todas las referencias suaves a objetos accesibles de forma suave se hayan borrado antes de que arroje un OutOfMemoryError.

Referencias fantasmas

Las referencias fantasmas son las más débiles de todos los tipos de referencia, llamar a get on siempre devolverá nulo. Se hace referencia fantasma a un objeto después de que se ha finalizado, pero antes de que se haya recuperado su memoria asignada, a diferencia de las referencias débiles que se ponen en cola antes de que se finalicen o las referencias fantasmas GC'd rara vez se usen.

Entonces, ¿cómo son útiles? Cuando construye una referencia fantasma, siempre debe pasar un ReferenceQueue. Esto indica que puede usar una referencia fantasma para ver cuándo su objeto es GC'd.

Oye, así que si las referencias débiles se ponen en cola cuando se consideran finalizadas pero aún no GC'd, podríamos crear una nueva referencia fuerte al objeto en el bloque finalizador y evitar que el objeto sea GC'd. Sí, puedes pero probablemente no deberías hacer esto. Para verificar este caso, el ciclo GC ocurrirá al menos dos veces para cada objeto a menos que ese objeto sea accesible solo por una referencia fantasma. Esta es la razón por la que puede quedarse sin almacenamiento dinámico incluso cuando su memoria contiene mucha basura. Las referencias fantasmas pueden evitar esto.

Puede leer más en mi artículo Tipos de referencias en Java (Strong, Soft, Weak, Phantom) .

Naresh Joshi
fuente
usted escribió que las referencias débiles serán GC'ed en el próximo ciclo si no se refrenan de otras referencias ... pero ¿no debería suceder lo mismo con las referencias fuertes? si no se accede a la referencia fuerte de ninguna manera, entonces se borra ... entonces, si es así, ¿dónde está la diferencia nuevamente? #confused
filemonczyk
1
Si se hace referencia a un objeto, digamos s1 (fuerte) y s2 (fuerte), el objeto no será elegible para la recolección de basura hasta que s1 y s2 estén desreferenciados, pero si el objeto se deriva de s1 (débil) y s2 ( fuerte), entonces el objeto será elegible para la recolección de basura en el próximo ciclo de GC cuando se desreferencia de s2 solamente, porque s1 es una referencia débil y si el objeto no tiene ninguna otra referencia, excepto la débil, es elegible para GC
Naresh Joshi