¿Cuándo utilizarías WeakHashMap o WeakReference?

El uso de referencias débiles es algo que nunca he visto en una implementación, así que estoy tratando de descubrir cuál es el caso de uso para ellos y cómo funcionaría la implementación. ¿Cuándo necesitó utilizar WeakHashMap o WeakReference y cómo se usó?

    Un problema con las referencias fuertes es el almacenamiento en caché, en particular con estructuras muy grandes como imágenes. Supongamos que tiene una aplicación que tiene que funcionar con imágenes proporcionadas por el usuario, como la herramienta de diseño de sitios web en la que trabajo. Naturalmente, desea almacenar en caché estas imágenes, ya que cargarlas desde el disco es muy caro y desea evitar la posibilidad de tener dos copias de la imagen (potencialmente gigantesca) en la memoria a la vez.

    Como se supone que una memoria caché de imágenes nos impide recargar imágenes cuando no las necesitamos, se dará cuenta rápidamente de que la memoria caché siempre debe contener una referencia a cualquier imagen que ya esté en la memoria. Sin embargo, con referencias fuertes ordinarias, esa referencia forzará a la imagen a permanecer en la memoria, lo que requiere que determine de alguna manera cuándo la imagen ya no se necesita en la memoria y la elimine de la memoria caché para que sea elegible para la recolección de basura. Se ve obligado a duplicar el comportamiento del recolector de elementos no utilizados y determinar manualmente si un objeto debe estar o no en la memoria.

    Comprensión de las referencias débiles , Ethan Nicholas

    Una distinción que debe ser clara es la diferencia entre una WeakReference y una SoftReference .

    Básicamente, una WeakReference hará una WeakReference con entusiasmo, una vez que el objeto al que se hace referencia no tenga referencias duras . SoftReference otro lado, un objeto d SoftReference tenderá a ser dejado por el recolector de basura hasta que realmente necesite reclamar la memoria.

    Un caché donde los valores se mantienen dentro de WeakReference sería bastante inútil (en un WeakHashMap , son las claves las que están débilmente referenciadas). SoftReferences son útiles para ajustar los valores cuando se desea implementar un caché que puede crecer y reducirse con la memoria disponible

    Un uso común de WeakReference y WeakHashMap en particular es para agregar propiedades a los objetos. Ocasionalmente, desea agregar alguna funcionalidad o datos a un objeto, pero la creación de subclases y / o la composición no son una opción; en ese caso, lo más obvio sería crear un hashmap que vincule el objeto que desea extender con la propiedad que desea agregar. . luego, cuando necesite la propiedad, puede buscarla en el mapa. Sin embargo, si los objetos a los que está agregando propiedades tienden a destruirse y crearse mucho, puede terminar con muchos objetos viejos en el mapa que ocupan mucha memoria.

    Si utiliza un WeakHashMap los objetos saldrán de su mapa tan pronto como ya no sean utilizados por el rest de su progtwig, que es el comportamiento deseado.

    Tuve que hacer esto para agregar algunos datos a java.awt.Component para java.awt.Component un cambio en el JRE entre 1.4.2 y 1.5, lo podría haber arreglado JButton cada componente que estaba interesado int ( JButton , JFrame , JPanel . …) pero esto fue mucho más fácil con mucho menos código.

    Otro caso útil para WeakHashMap y WeakReference es la implementación de un registro de escucha .

    Cuando creas algo que quiere escuchar ciertos eventos, generalmente registras un oyente, por ej.

     manager.registerListener(myListenerImpl); 

    Si el manager almacena su oyente con una WeakReference , eso significa que no necesita eliminar el registro, por ejemplo, con un manager.removeListener(myListenerImpl) porque se eliminará automáticamente una vez que su oyente o su componente que contiene el oyente no estén disponibles.

    Por supuesto, aún puede eliminar manualmente su oyente, pero si no lo hace o lo olvida, no causará una pérdida de memoria, y no evitará que su oyente sea recolectado.

    ¿Dónde entra WeakHashMap en la imagen?

    El registro de escucha que desea almacenar oyentes registrados como WeakReference necesita una colección para almacenar estas referencias. No hay implementación WeakHashSet en la biblioteca Java estándar solo WeakHashMap pero podemos usar fácilmente la última para “implementar” la funcionalidad de la primera:

     Set listenerSet = Collections.newSetFromMap(new WeakHashMap()); 

    Con este listenerSet para registrar un nuevo oyente, solo tiene que agregarlo al conjunto, e incluso si no se elimina explícitamente, si ya no se hace referencia al oyente, la JVM lo eliminará automáticamente.

    Si, por ejemplo, desea realizar un seguimiento de todos los objetos creados de una determinada clase. Para permitir aún que estos objetos sean basura, se mantiene una lista / mapa de referencias débiles a los objetos en lugar de los objetos mismos.

    Ahora si alguien pudiera explicarme referencias fantasmas, estaría feliz …

    Un uso del mundo real que tuve para WeakReferences es si tienes un solo objeto muy grande que rara vez se usa. No desea mantenerlo en la memoria cuando no es necesario; pero, si otro hilo necesita el mismo objeto, tampoco quieres dos de ellos en la memoria. Puede mantener una referencia débil al objeto en alguna parte, y referencias difíciles en los métodos que lo usan; cuando los métodos terminen, el objeto será recolectado.

    Esta publicación de blog demuestra el uso de ambas clases: Java: sincronización en una ID . El uso es algo como esto:

     private static IdMutexProvider MUTEX_PROVIDER = new IdMutexProvider(); public void performTask(String resourceId) { IdMutexProvider.Mutex mutext = MUTEX_PROVIDER.getMutex(resourceId); synchronized (mutext) { // look up the resource and do something with it } } 

    IdMutextProvider proporciona objetos basados ​​en id para sincronizar. Los requisitos son:

    • debe devolver una referencia al mismo objeto para el uso concurrente de ID equivalentes
    • debe devolver un objeto diferente para diferentes ID
    • sin mecanismo de liberación (los objetos no se devuelven al proveedor)
    • no debe tener fugas (los objetos no utilizados son elegibles para la recolección de basura)

    Esto se logra usando un mapa de almacenamiento interno de tipo:

     WeakHashMap> 

    El objeto es clave y valor. Cuando nada externo al mapa tiene una referencia difícil al objeto, puede ser basura recolectada. Los valores en el mapa se almacenan con referencias duras, por lo que el valor debe estar envuelto en una WeakReference para evitar una pérdida de memoria. Este último punto está cubierto en el javadoc .

    Como se indicó anteriormente, la referencia débil se mantiene mientras exista una referencia fuerte.

    Un ejemplo de uso sería usar WeakReference dentro de los oyentes, de modo que los oyentes ya no estén activos una vez que la referencia principal a su objeto objective haya desaparecido. Tenga en cuenta que esto no significa que la WeakReference se elimine de la lista de oyentes, todavía se requiere limpieza, pero puede realizarse, por ejemplo, en horarios progtwigdos. Esto también tiene el efecto de evitar que el objeto escuchado contenga referencias fuertes y, finalmente, ser una fuente de saturación de memoria. Ejemplo: componentes de la GUI de Swing que hacen referencia a un modelo que tiene un ciclo de vida más largo que la ventana.

    Mientras jugaba con los oyentes como se describió anteriormente nos dimos cuenta rápidamente de que los objetos se recogen “inmediatamente” desde el punto de vista del usuario.

    Hice una búsqueda de código de google para “nuevo WeakHashMap ()”.

    Obtuve un montón de coincidencias del proyecto GNU classpath y

    1. Proyecto Apache xbean: WeakHashMapEditor.java
    2. Proyecto Apache Lucene: CachingWrapperFilter.java

    puede usar weakhashmap para implementar un caché libre de recursos para la creación de objetos expansivos.

    pero tenga en cuenta que no es deseable tener objetos mutables. Lo usé para almacenar en caché los resultados de las consultas (que tardan unos 400 ms en ejecutarse) en un motor de búsqueda de texto, que rara vez se actualiza.