trabajo tipos sobre sensorial plazo memoria libros largo corto cientificos articulos java unit-testing junit out-of-memory testng

java - tipos - memoria sensorial



Prueba de unidad Java: cómo medir la huella de memoria para la llamada de método (4)

Asumiendo que tengo una clase que hace un procesamiento pesado, operando con varias colecciones. Lo que quiero hacer es asegurarme de que tal operación no pueda llevar a la falta de memoria o incluso mejor. Quiero establecer un umbral de cuánta memoria puede usar.

class MyClass() { public void myMethod() { for(int i=0; i<10000000; i++) { // Allocate some memory, may be several collections } } } class MyClassTest { @Test public void myMethod_makeSureMemoryFootprintIsNotBiggerThanMax() { new MyClass().myMethod(); // How do I measure amount of memory it may try to allocate? } }

¿Cuál es el enfoque correcto para hacer esto? O esto no es posible / no es factible?


Aquí hay un ejemplo de Netty que hace algo similar: MemoryAwareThreadPoolExecutor . La clase de caché de Guava también tiene un desalojo basado en el tamaño. Puede ver estas fuentes y copiar lo que están haciendo. En particular, aquí está cómo Netty está estimando tamaños de objetos . En esencia, estimarías el tamaño de los objetos que generas en el método y mantendrás un conteo.

Obtener información general de la memoria (por ejemplo, cuánto montón está disponible / usado) le ayudará a decidir cuánto uso de memoria asignar al método, pero no a la cantidad de memoria utilizada por las llamadas al método individual.

Habiendo dicho eso, es muy raro que legítimamente necesites esto. En la mayoría de los casos, limitar el uso de la memoria limitando cuántos objetos pueden estar allí en un punto determinado (por ejemplo, mediante el uso de una cola limitada) es suficiente y es mucho más fácil de implementar.


Para medir el uso de la memoria actual, use:

Runtime.getRuntime().freeMemory() , Runtime.getRuntime().totalMemory()

Aquí hay un buen ejemplo: obtener información del sistema a nivel del sistema operativo

Pero esta medida no es precisa, pero puede proporcionarle mucha información. Otro problema es con GC que es impredecible.


Puede usar el generador de perfiles (por ejemplo, JProfiler) para ver el uso de la memoria por clases. O, cómo se menciona Areo, solo imprime el uso de la memoria:

Runtime runtime = Runtime.getRuntime(); long usedMemoryBefore = runtime.totalMemory() - runtime.freeMemory(); System.out.println("Used Memory before" + usedMemoryBefore); // working code here long usedMemoryAfter = runtime.totalMemory() - runtime.freeMemory(); System.out.println("Memory increased:" + (usedMemoryAfter-usedMemoryBefore));


Puedo pensar en varias opciones:

  • Averiguar cuánta memoria requiere su método a través de un microbenchmark (es decir, jmh ).
  • Construyendo estrategias de asignación basadas en estimación heurística. Existen varias soluciones de código abierto que implementan la estimación del tamaño de clase, es decir, ClassSize . Una forma mucho más fácil podría ser utilizar un caché que libera objetos raramente utilizados (es decir, caché de guayaba). Como menciona @EnnoShioji, el caché de Guava tiene políticas de desalojo basadas en la memoria.

También puede escribir su propia prueba de referencia que cuenta la memoria. La idea es

  1. Tener un solo hilo ejecutándose.
  2. Crea una nueva matriz para almacenar tus objetos para asignar. Entonces estos objetos no serán recolectados durante la ejecución de GC.
  3. System.gc() , memoryBefore = runtime.totalMemory() - runtime.freeMemory()
  4. Asigna tus objetos. Póngalos en la matriz.
  5. System.gc() , memoryAfter = runtime.totalMemory() - runtime.freeMemory()

Esta es una técnica que utilicé en mi herramienta ligera de micro-referencia que es capaz de medir la asignación de memoria con precisión byte.