2011-04-22 11 views
10

Estoy en camino con la implementación de un mecanismo de almacenamiento en caché para mi aplicación Android.SoftReference obtiene basura recogida demasiado pronto

Uso SoftReference, como muchos ejemplos que he encontrado. El problema es que cuando me desplazo hacia arriba o hacia abajo en mi ListView, la más de las imágenes ya está borrada. Puedo ver en LogCat que mi aplicación es basura recolectada cada vez que la aplicación carga imágenes nuevas. Eso significa que más de las imágenes no visibles en ListView se han ido.

Por lo tanto, cada vez que pergamino a una posición anterior (en el que realmente descargado las imágenes antes) Tengo que descargar las imágenes una vez más - que son no en caché.

También he investigado este tema. According to Mark Murphy in this article, parece que hay (o era?) Un error con el SoftReference. Algunos otros resultados indican lo mismo (o el mismo resultado); SoftReference s están siendo retirados demasiado temprano.

¿Existe alguna solución de trabajo?

+2

** demasiado ** temprano? si hay una necesidad de memoria, se borrará. ¿quién puede decir que es demasiado temprano? si el sistema quiere borrarlo, esto es lo que es la referencia suave. – binnyb

+0

Correcto. Pero no hay necesidad de más memoria, ya que puedo colocar fácilmente alrededor de 50 imágenes en la memoria. Pero para evitar un error OOM, necesito usar este mecanismo de almacenamiento en caché. – Wroclai

+0

sugiero que guardes en caché cada imagen, de esa manera, cuando se borre, no tienes que buscarla desde la web (a menos que no exista en la memoria caché) – binnyb

Respuesta

16

SoftReference son los pobres Caché de hombre. La JVM puede mantener viva la referencia durante más tiempo, pero no es necesario. Tan pronto como ya no haya una referencia difícil, la JVM puede recoger un objeto de referencia suave. El comportamiento de la JVM que está experimentando es correcto, ya que la JVM no tiene que mantener dicho objeto por más tiempo. Por supuesto, la mayoría de las JVM intentan mantener vivo el objeto de referencia suave hasta cierto punto.

Por lo tanto, SoftReferences es un caché peligroso. Si realmente desea garantizar un comportamiento de almacenamiento en caché, necesita un caché real. Como un LRU-cache. Especialmente si el almacenamiento en caché es crítico para el rendimiento, debe usar un caché adecuado.

+0

¡Claro respuesta! ¡Gracias! Buscaré en el LRU-caché y veré si es lo que estoy buscando. Pero, ¿por qué la JVM no contiene la referencia suave "un poco más"? En realidad, queda memoria ... – Wroclai

+3

Porque no es necesario. Su comprensión del contrato de SR es incorrecta. GC no quiere "posponer" la limpieza de SR hasta el momento OOM, porque simplemente no tiene tiempo para hacerlo sin afectar el rendimiento de las aplicaciones. –

+0

@road to yamburg: ¡Gracias por aclarar eso! – Wroclai

2

Guarde en caché cada imagen en el almacenamiento persistente en lugar de solo en la memoria.

+0

¿Almacenamiento persistente para un caché transitorio? Derecho. Esta es una solución. Por algún otro problema. –

+0

No está exactamente claro que esto deba ser un caché transitorio. –

1

La respuesta de Gamlor es correcta en su localización. Sin embargo, para obtener información adicional, consulte la GC FAQ, pregunta 32.

El servidor Java HotSpot VM utiliza el tamaño máximo posible del montón (según lo establecido por la opción -Xmx) para calcular el espacio libre restante.

Java HotSpot Client VM utiliza el tamaño de almacenamiento dinámico actual para calcular el espacio libre.

Esto significa que la tendencia general es que Server VM crezca el montón en lugar de vaciar referencias suaves, y -Xmx por lo tanto tiene un efecto significativo en cuando las referencias suaves son basura.

+1

tenga en cuenta que las aplicaciones de Android no se ejecutan en la JVM. – Jan

+0

Idealmente, Android mantendría las referencias suaves al menos por un tiempo, pero se necesita el hecho de que haya usado una referencia suave para indicar que no le importa si esa información desaparece y básicamente la borra al instante. La JVM hace esto correctamente. Android básicamente come todo lo que pueda con el recolector de basura. Así que JVM FAQ es más que inútil el problema anterior. La respuesta a la cual es básicamente usar referencias fuertes. – Tatarize

7

Desde el sitio de entrenamiento Android:

http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html

En el pasado, una popular aplicación caché de memoria era un SoftReference o caché WeakReference mapa de bits, sin embargo, esto no es recomendable. A partir de Android 2.3 (Nivel de API 9) el recolector de basura es más agresivo con la recopilación de referencias blandas/débiles que hace que bastante ineficaz. Además, antes de Android 3.0 (API nivel 11), , los datos de respaldo de un mapa de bits se almacenaron en la memoria nativa que no es lanzados de manera predecible, lo que podría causar que una aplicación exceda brevemente sus límites de memoria y falle.

Más información en el enlace.

Debemos usar LruCache en su lugar.

+0

¡Gracias! ¡Lo consideraré la próxima vez! – Wroclai

Cuestiones relacionadas