2010-05-18 17 views
18

Effective Java dice:¿Cómo evitar fugas de memoria en la devolución de llamada?

Una tercera fuente común de pérdidas de memoria es oyentes y otras devoluciones de llamada. Si implementa una API donde los clientes registran las devoluciones de llamada pero no las anulan explícitamente, se acumularán a menos que tome alguna acción de . La mejor forma de asegurarse de que las devoluciones de llamada son basura recogidas rápidamente es almacenar solo referencias débiles , por ejemplo, almacenándolas solo como claves en un WeakHashMap.

Soy un principiante en Java. ¿Podría alguien enseñarme cómo crear referencias débiles en las devoluciones de llamada y decirme cómo resuelven los problemas de pérdida de memoria? Gracias.

Respuesta

11

Leer this artículo

Las tiendas de comida para llevar clave son:

Se puede pensar en referencias directas como referencias fuertes que no requieren codificación adicional para crear o acceder al objeto . Los tres tipos restantes de referencias son subclases de la clase de referencia que se encuentran en el paquete java.lang.ref. Las referencias suaves son proporcionadas por la clase SoftReference , las referencias débiles por la clase WeakReference y las referencias phantom por PhantomReference.

Las referencias suaves actúan como una caché de datos. Cuando la memoria del sistema es baja, el recolector de basura puede liberar arbitrariamente un objeto cuya única referencia es una referencia suave. En otras palabras, si hay no hay referencias fuertes a un objeto, ese objeto es un candidato para la versión . El recolector de basura es necesario para liberar cualquier referencia suave antes de lanzar OutOfMemoryException.

Las referencias débiles son más débiles que las referencias suaves . Si las únicas referencias a un objeto son referencias débiles, el recolector de basura puede reclamar la memoria utilizada por un objeto en cualquier momento. No hay requisito para una situación de memoria baja. Normalmente, la memoria utilizada por el objeto se recupera en el siguiente paso del recolector de elementos no utilizados.

Las referencias fantasmas se relacionan con las tareas de limpieza . Ofrecen una notificación inmediatamente antes de que el recolector de basura realice el proceso de finalización y libere un objeto. Considere es una forma de hacer tareas de limpieza dentro de un objeto .

seguido de la lista WeakListModel que no publicaré para evitar saturar esta respuesta.

+0

me gustaría tener en cuenta que el enlace está roto – Maurice

+0

fijo, gracias por señalar esto. –

+1

Wow ardiente rápido! gracias – Maurice

8

para ilustrar el concepto con un ejemplo rápido (en bruto), considere lo siguiente:

public interface ChangeHandler { 
    public void handleChange(); 
} 

public class FileMonitor { 

    private File file; 
    private Set<ChangeHandler> handlers = new HashSet<ChangeHandler>(); 

    public FileMonitor(File file) { 
     this.file = file; 
    } 

    public void registerChangeHandler(ChangeHandler handler) { 
     this.handlers.add(handler); 
    } 

    public void unregisterChangeHandler(ChangeHandler handler) { 
     this.handlers.remove(handler); 
    } 

    ... 
} 

Si una clase de cliente utiliza esta API FileMonitor, que podrían hacer esto:

public class MyClass { 

    File myFile = new File(...); 
      FileMonitor monitor = new FileMonitor(myFile); 

    public void something() { 
     ... 
     ChangeHandler myHandler = getChangeHandler(); 
     monitor.registerChangeHandler(myHandler); 
     ... 
    } 
} 

Si el autor del MyClass luego se olvida de llamar al unregisterChangeHandler() cuando se hace con el controlador, FileMonitorHashSet referenciará para siempre la instancia que se registró, causando que permanezca en la memoria hasta el FileMonitor se destruye o la aplicación se cierra.

Para evitar esto, Bloch sugiere utilizar una colección de referencia débil en lugar del HashSet, de modo que si se destruye su instancia de MyClass, la referencia se eliminará de la colección del monitor.

Es posible reemplazar el HashSet en FileMonitor con un WeakHashMap y utilizar los manipuladores como las claves, ya que este último se eliminará automáticamente el controlador de la colección cuando todas las demás referencias al objeto se han ido.

+1

Gracias por el ejemplo, pero todavía no entiendo muy bien. Cuando algo() retorna, la referencia fuerte myHandler saldrá del alcance. ¿No es así que el manejador al que hace referencia WeakHashMap se puede destruir en cualquier momento (incluso si la instancia de MyClass permanece)? Eso no es lo que quieres, ¿verdad? – kodu

+0

Ah, estoy empezando a ver ... Podría usar WeakHashMap , entonces la clave es, de hecho, la instancia de MyClass. – kodu

+0

Creo que myHandler debería ir después de que algo() regrese, incluso si la instancia de MyClass permanece. entonces WeakHashMap es mejor que WeakHashMap yuxh

Cuestiones relacionadas