solucion - java.lang.outofmemoryerror: gc overhead limit exceeded r
Cuándo recolectar basura (8)
Tengo un código que carga una imagen muy grande en la memoria. Por lo tanto, parecía razonable llamar
System.gc();
antes de cargar la imagen Por lo que puedo decir, funciona sin problemas.
Ayer decidí usar un software muy útil llamado FindBugs que escanea tu código e informa sobre problemas que pueden causar errores o estrategias generalmente no recomendadas. El problema es que este pedazo de código que mencioné se informa. La descripción es esta:
... fuerza la recolección de basura; extremadamente dudoso, excepto en el código de evaluación comparativa
Y continúa para elaborar:
El código invoca explícitamente la recolección de basura. Excepto por el uso específico en la evaluación comparativa, esto es muy dudoso.
En el pasado, las situaciones en las que las personas han invocado explícitamente al recolector de basura en rutinas como métodos de cierre o finalización han dado lugar a enormes agujeros negros de rendimiento. La recolección de basura puede ser costosa. Cualquier situación que fuerce cientos o miles de recolecciones de basura llevará a la máquina a un rastreo.
Entonces mi pregunta es: ¿NO está BIEN llamar programáticamente al recolector de basura en tal caso? Mi código solo lo llama una vez y el método en el que se usa rara vez se usa. Y si no está bien llamarlo, ¿qué debe hacer en caso de que necesite tanta memoria como sea posible antes de realizar una operación que requiere mucha memoria y necesita liberar la mayor cantidad de memoria posible antes de hacerlo?
¿Obtuviste alguna mejora de rendimiento con System.gc ()? No lo creo, ya que probablemente no tenga muchos objetos que deba recolectar antes de cargar la imagen.
Por lo general, los recolectores de basura modernos saben cuándo se debe ejecutar, por lo que no deberías forzar una colección, a menos que tengas una muy buena razón para hacerlo. (por ejemplo, una aplicación de evaluación comparativa tal como lo sugiere ese complemento)
Por cierto: al llamar a System.gc (), se recomienda que la VM realice una recopilación "completa" o "grande", lo que significa que todos los subprocesos se detienen en breve. De lo contrario, probablemente solo haga recolecciones de basura "pequeñas", lo que no detiene todos los hilos.
Ejecute su programa con -verbose: gc para ver cuántos bytes se recopilan.
También hay mucha información técnica sobre recolección de basura aquí: http://java.sun.com/developer/technicalArticles/Programming/GCPortal/
Asegúrese de que los objetos grandes se puedan activar lo antes posible. Es decir, establecer variables nulas y / o dejarlas fuera del alcance. ¡Esto ayuda!
En general, no. No es apropiado llamar a System.gc (). Sin embargo, he tenido algunos casos en los que tenía sentido.
En el software que escribo, hay una capa de seguimiento de rendimiento incorporada. Se usa principalmente durante las pruebas automatizadas, pero se puede utilizar en el campo con fines de diagnóstico. Entre pruebas o después de ejecuciones específicas, llamaremos a System.gc varias veces y luego registraremos la memoria aún presente. Nos proporciona un punto de referencia básico de la huella de memoria para observar líneas de tendencia de consumo de memoria a lo largo del tiempo. Si bien esto se puede hacer con algunas de las interfaces JVM externas, fue más fácil hacerlo en su lugar y no se requirieron números exactos.
En un sistema mucho más antiguo, podríamos tener más de 72 JVM separadas (sí, 72, había una buena razón para ello en el momento de la construcción). En ese sistema, dejar el montón flotando libremente en las 72 JVM podría generar un consumo de memoria total excesivo (más allá de la memoria física). Se invocó a System.gc () entre los ejercicios de datos pesados para tratar de mantener la JVM más cerca del promedio para evitar que el montón crezca (limitar el montón podría haber sido otra dirección, pero habría requerido que los implementadores configuren más por sitio y ser más consciente de lo que sucedía bajo el capó para hacerlo bien y no hacer que el sistema falle bajo carga).
Está bien llamar al recolector de basura, no obtienes ningún "problema". Sin embargo, dudo que signifique un rendimiento excelente, a menos que esa llamada también trate de desfragmentar los datos asignados. No lo sé
Lo que debes hacer en este caso es perfilar el código. Ejecútelo varias veces, vea qué tipo de resultados obtiene.
Normalmente, el GC es más inteligente que usted, por lo que es mejor dejarlo funcionar cada vez que decida el tiempo de ejecución. Si el tiempo de ejecución necesita memoria, ejecutará el propio GC
Por lo general, no debe interferir con el recolector de basura. Si es necesario liberar algo de memoria antes de cargar la imagen, el recolector de basura lo hará por usted.
De todos modos, si solo lo haces una vez, es probable que no afecte drásticamente tu rendimiento. Las cosas hechas en bucles son mucho más importantes.
Si falla la asignación de memoria, se inicia un ciclo de GC y se intenta nuevamente la asignación.
Ya recibiste muchos buenos consejos, que intentaré no reiterar.
Si realmente tiene problemas con el GC, como paradas completas de su aplicación por un segundo, haga lo siguiente: 1. compruebe que no haya ninguna llamada a System.gc (); 2. echa un vistazo a las diversas opciones para configurar el gc. Hay muchos de ésos alrededor, y son mucho más útiles, luego fuerzan a gc.