usar sirve settitle que para codigo java caching soft-references

sirve - ¿Cómo hacer que el sistema de Java lance Soft References?



title java (5)

  1. Establezca el parámetro -Xmx en un valor muy pequeño.
  2. Prepara tu referencia suave
  3. Crea tantos objetos como sea posible. Solicite el objeto cada vez hasta que vuelva a solicitarlo desde el servidor.

Esta es mi pequeña prueba. Modificar según su necesidad.

@Test public void testSoftReference() throws Exception { Set<Object[]> s = new HashSet<Object[]>(); SoftReference<Object> sr = new SoftReference<Object>(new Object()); int i = 0; while (true) { try { s.add(new Object[1000]); } catch (OutOfMemoryError e) { // ignore } if (sr.get() == null) { System.out.println("Soft reference is cleared. Success!"); break; } i++; System.out.println("Soft reference is not yet cleared. Iteration " + i); } }

Voy a usar un caché basado en SoftReference (una cosa bastante simple por sí misma). Sin embargo, me encontré con un problema al escribir una prueba para ello.

El objetivo de la prueba es verificar si la memoria caché solicita nuevamente al servidor el objeto previamente almacenado en caché después de que se realiza la limpieza de la memoria.

Aquí encuentro el problema de cómo hacer que el sistema libere objetos de referencia suave. Llamar a System.gc () no es suficiente porque las referencias blandas no se liberarán hasta que la memoria esté baja. Estoy ejecutando esta prueba de unidad en la PC, por lo que el presupuesto de memoria para la máquina virtual podría ser bastante grande.

================== Agregado más adelante ==============================

¡Gracias a todos los que se cuidaron de responder!

Después de considerar todos los pros y contras, he decidido ir por el camino de la fuerza bruta según lo aconsejado por nanda y jarnbjo . Sin embargo, parece que JVM no es tan tonto: ni siquiera intentará la recolección de basura si solicita un bloqueo que, por sí solo, es mayor que el presupuesto de memoria de VM. Así que he modificado el código así:

/* Force releasing SoftReferences */ try { final List<long[]> memhog = new LinkedList<long[]>(); while(true) { memhog.add(new long[102400]); } } catch(final OutOfMemoryError e) { /* At this point all SoftReferences have been released - GUARANTEED. */ } /* continue the test here */


En lugar de un bucle de larga duración (como lo sugiere nanda), probablemente sea más rápido y más fácil simplemente crear una enorme matriz primitiva para asignar más memoria que la que está disponible para la VM, luego capturar e ignorar el OutOfMemoryError:

try { long[] foo = new long[Integer.MAX_VALUE]; } catch(OutOfMemoryError e) { // ignore }

Esto borrará todas las referencias débiles y blandas, a menos que su VM tenga más de 16 GB de almacenamiento disponible.


Esta pieza de código obliga a la JVM a eliminar todas las referencias de software. Y es muy rápido de hacer.

Funciona mejor que el enfoque Integer.MAX_VALUE, ya que aquí la JVM realmente intenta asignar tanta memoria.

try { Object[] ignored = new Object[(int) Runtime.getRuntime().maxMemory()]; } catch (OutOfMemoryError e) { // Ignore }

Ahora uso este bit de código en todas partes donde necesito un código de prueba de unidad utilizando SoftReferences.

Actualización : este enfoque funcionará solo con menos de 2G de memoria máxima.

Además, hay que tener mucho cuidado con SoftReferences. Es tan fácil mantener una referencia difícil por error que anulará el efecto de SoftReferences.

Aquí hay una prueba simple que muestra que funciona cada vez que funciona OSX. Estaría interesado en saber si el comportamiento de JVM es el mismo en Linux y Windows.

for (int i = 0; i < 1000; i++) { SoftReference<Object> softReference = new SoftReferencelt<Object>(new Object()); if (null == softReference.get()) { throw new IllegalStateException("Reference should NOT be null"); } try { Object[] ignored = new Object[(int) Runtime.getRuntime().maxMemory()]; } catch (OutOfMemoryError e) { // Ignore } if (null != softReference.get()) { throw new IllegalStateException("Reference should be null"); } System.out.println("It worked!"); }


Podría establecer explícitamente la referencia suave como nula en su prueba y, como tal, simular que la referencia suave se ha liberado.

Esto evita cualquier configuración de prueba complicada que dependa de la memoria y la recolección de basura.


Una mejora que funcionará para más de 2G de memoria máx. Se repite hasta que se produce un error OutOfMemory.

@Test public void shouldNotHoldReferencesToObject() { final SoftReference<T> reference = new SoftReference<T>( ... ); // Sanity check assertThat(reference.get(), not(equalTo(null))); // Force an OoM try { final ArrayList<Object[]> allocations = new ArrayList<Object[]>(); int size; while( (size = Math.min(Math.abs((int)Runtime.getRuntime().freeMemory()),Integer.MAX_VALUE))>0 ) allocations.add( new Object[size] ); } catch( OutOfMemoryError e ) { // great! } // Verify object has been garbage collected assertThat(reference.get(), equalTo(null)); }