platzi introduccion gratis cursos curso basicos basico aprender java memory memory-management garbage-collection

introduccion - java basico platzi



Encontrar uso de memoria en Java (8)

Es completamente normal que una JVM alcance el 100% de uso de memoria y vuelva a decir un 10% después de un GC y lo haga cada pocos segundos.

No debería necesitar intentar administrar la memoria de esta manera. No se puede decir cuánta memoria se conserva hasta que se haya ejecutado un GC completo.

Sugiero que trabajes lo que realmente intentas lograr y veas el problema de otra manera.

A continuación está el escenario que necesito resolver. He golpeado con dos soluciones.

Necesito mantener un caché de datos obtenidos de la base de datos para que se muestren en una GUI de Swing. Siempre que mi memoria JVM exceda el 70% de su memoria asignada, debo advertir al usuario sobre el uso excesivo. Y una vez que el uso de memoria JVM excede el 80%, entonces tengo que detener toda la consulta de la base de datos y limpiar la memoria caché existente recuperada como parte de las operaciones del usuario y notificar al usuario. Durante el proceso de limpieza, manejaré manualmente eliminar algunos datos basados ​​en algunas reglas e instruiré a JVM para un GC. Siempre que se produzca GC, si la memoria se limpia y alcanza el 60% de la memoria asignada, necesito reiniciar todo el manejo de la Base de datos y devolver el control al usuario.

Para verificar las estadísticas de la memoria JVM encontré las siguientes dos soluciones. No pudo decidir cuál es la mejor manera y por qué.

  1. Runtime.freeMemory (): el subproceso creado para ejecutarse cada 10 segundos y comprobar la memoria libre y si la memoria excede los límites mencionados, las ventanas emergentes necesarias intimarán al usuario y llamarán a los métodos para detener las operaciones y liberar la memoria.

  2. MemoryPoolMXBean.getUsage () - Java 5 ha introducido JMX para obtener la instantánea de la memoria en tiempo de ejecución. En, JMX no puedo usar la notificación de Umbral ya que solo notificará cuando la memoria alcance / exceda el umbral dado. La única forma de usar es Polling en MemoryMXBean y verifique las estadísticas de memoria durante un período.

En caso de usar encuestas, me parece que las implementaciones van a ser las mismas.

Sugiera las ventajas de los métodos y si hay otras alternativas / correcciones a los métodos que se usan.


Los requisitos que menciona son una clara contradicción con el funcionamiento de Garbage Collection en una JVM.

Debido al comportamiento de la JVM, será muy difícil advertirles a los usuarios de manera correcta. En general, detener la manipulación de la base de datos, limpiar cosas y comenzar de nuevo realmente no es el camino a seguir.

Deje que la JVM haga lo que se supone que debe hacer, maneje toda la memoria relacionada por usted. Las generaciones modernas de JVM son muy buenas en eso y con algunos ajustes finos de los parámetros del GC obtendrás un manejo de memoria mucho más limpio y luego forzar las cosas tú mismo

Artículos como http://www.kodewerk.com/advice_on_jvm_heap_tuning_dont_touch_that_dial.htm mencionan los pros y los contras y ofrecen una buena explicación de lo que la VM hace por usted


Mire en JConsole. Grafica la información que necesita, por lo que se trata de adaptarla a sus necesidades (dado que se ejecuta en Sun Java 6).

Esto también le permite separar el proceso de vigilancia de lo que desea observar.


Solo he usado el primer método para una tarea similar y estaba bien.

Una cosa que debes tener en cuenta, para ambos métodos, es implementar algún tipo de antirrebote, es decir, una vez que reconozcas que alcanzas el 70% de la memoria, espera un minuto (o en cualquier otro momento que consideres apropiado), el GC puede funcionar en ese momento tiempo y limpiar mucha memoria.

Si implementa un gráfico Runtime.freeMemory () en su sistema, verá cómo la memoria sube y baja constantemente, hacia arriba y hacia abajo.


La forma habitual de manejar este tipo de cosas es usar WeakReference sy SoftReference s. Necesita usar ambos: la referencia débil significa que no tiene varias copias de las cosas, y las referencias suaves significan que el GC se mantendrá en las cosas hasta que se quede sin memoria.

Si necesita realizar una limpieza adicional, puede agregar referencias a las colas y anular los métodos de notificación de colas para activar la limpieza. Es muy divertido, pero necesitas entender lo que hacen estas clases.


VisualVM es un poco más agradable que JConsole porque te ofrece una buena vista visual del recolector de basura.


Muy tarde después de la publicación original, lo sé, pero pensé en publicar un ejemplo de cómo lo hice. Espero que sea de alguna utilidad para alguien (insisto, es una prueba del ejemplo principal, nada más ... tampoco particularmente elegante :))

Solo pega estas dos funciones en una clase, y debería funcionar.

EDITAR: Ah, e import java.util.ArrayList; import java.util.List; import java.util.ArrayList; import java.util.List;

public static int MEM(){ return (int)(Runtime.getRuntime().maxMemory()-Runtime.getRuntime().totalMemory() +Runtime.getRuntime().freeMemory())/1024/1024; } public static void main(String[] args) throws InterruptedException { List list = new ArrayList(); //get available memory before filling list int initMem = MEM(); int lowMemWarning = (int) (initMem * 0.2); int highMem = (int) (initMem *0.8); int iteration =0; while(true) { //use up some memory list.add(Math.random()); //report if(++iteration%10000==0) { System.out.printf("Available Memory: %dMb /tListSize: %d/n", MEM(),list.size()); //if low on memory, clear list and await garbage collection before continuing if(MEM()<lowMemWarning) { System.out.printf("Warning! Low memory (%dMb remaining). Clearing list and cleaning up./n",MEM()); //clear list list = new ArrayList(); //obviously, here is a good place to put your warning logic //ensure garbage collection occurs before continuing to re-add to list, to avoid immediately entering this block again while(MEM()<highMem) { System.out.printf("Awaiting gc...(%dMb remaining)/n",MEM()); //give it a nudge Runtime.getRuntime().gc(); Thread.sleep(250); } System.out.printf("gc successful! Continuing to fill list (%dMb remaining). List size: %d/n",MEM(),list.size()); Thread.sleep(3000); //just to view output } } } }

EDITAR: Sin embargo, este enfoque todavía se basa en la configuración razonable de la memoria en el jvm utilizando -Xmx.

EDIT2: Parece que la línea de solicitud de GC realmente ayuda con las cosas, al menos en mi JVM. ymmv.


Solo una nota al margen: Runtime.freeMemory() no indica la cantidad de memoria que queda de asignación, solo es la cantidad de memoria que está libre dentro de la memoria actualmente asignada (que inicialmente es más pequeña que la memoria máxima a la que la VM está configurada uso), pero crece con el tiempo.

Al iniciar una VM, la memoria máxima ( Runtime.maxMemory() ) solo define el límite superior de memoria que la VM puede asignar (configurable mediante la opción -Xmx VM). La memoria total ( Runtime.totalMemory() ) es el tamaño inicial de la memoria asignada para el proceso de la máquina virtual (configurable mediante la opción -Xms VM), y crecerá dinámicamente cada vez que asigne más que la parte libre de la misma ( Runtime.freeMemory() ), hasta que alcanza la memoria máxima.

La métrica que le interesa es la memoria disponible para una asignación adicional:

long usableFreeMemory= Runtime.getRuntime().maxMemory() -Runtime.getRuntime().totalMemory() +Runtime.getRuntime().freeMemory()

o:

double usedPercent=(double)(Runtime.getRuntime().totalMemory() -Runtime.getRuntime().freeMemory())/Runtime.getRuntime().maxMemory()