2009-07-18 19 views
8

Tengo un código que carga una imagen muy grande en la memoria. Por lo tanto, parecía razonable llamar aCuándo recoger basura

System.gc(); 

antes de cargar la imagen. Por lo que puedo decir, funciona sin problemas.

Ayer decidí utilizar una pieza bastante útil de software llamada FindBugs que escanea su 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 la siguiente:

... fuerzas de recolección de basura; extremadamente dudosa excepto en código evaluación comparativa

Y sigue para elaborar:

Código invoca explícitamente la basura colección. Excepto para uso específico en el análisis comparativo , esto es muy dudoso.

En el pasado, las situaciones donde la gente han invocado explícitamente el recolector de basura en las rutinas tales como los métodos de finalización y cierre o ha dado lugar a enormes agujeros negros rendimiento. La recolección de basura puede ser costosa. Cualquier situación de que fuerce cientos o miles de recolecciones de basura será llevar la máquina a un rastreo.

Así que mi pregunta es: ¿NO ES ACEPTABLE llamar programáticamente al recolector de basura en ese 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?

+1

En este caso, probablemente esté serializando el rendimiento. Si deja que el GC decida cuándo ejecutar, puede que se ejecute cuando la aplicación está bloqueando en E/S. –

+0

P: Cuándo llamar a System.gc(). A: nunca – KitsuneYMG

+1

wow que fue idea completa. Entiendo totalmente por qué nunca debería llamar a gc por tu respuesta. Muchas gracias. –

Respuesta

9

¿Obtuvo 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 mejor cuándo funcionar, por lo que no deberías forzar una recolección, a menos que tengas una muy buena razón para hacerlo. (Por ejemplo, una aplicación de evaluación comparativa sugerida por ese complemento)

btw: Calling System.gc() 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 un montón de información técnica en la recolección de basura aquí: http://java.sun.com/developer/technicalArticles/Programming/GCPortal/

+4

System.gc() no "fuerza" nada. La máquina virtual es libre de ignorarlo. La redacción en Javadoc es "Llamar al método gc * sugiere * que la Máquina Virtual Java gaste esfuerzos para reciclar objetos no utilizados" (énfasis mío) –

+2

-1 por NO LEER el javadoc en System.gc() como dijo Adrian, obliga nada. http://stackoverflow.com/questions/1147511/how-can-i-imate-amount-of-memory-left-with-calling-system-gc/1149182#1149182 for real forcing gc – KitsuneYMG

1

Está bien llamar al recolector de basura, no obtiene ningún "problema" de ello. Sin embargo, dudo que signifique un aumento sustancial en el rendimiento, a menos que esa llamada también trate de desfragmentar los datos asignados. No lo sé

Lo que debe hacer en este caso es crear un perfil del código. Ejecútelo varias veces, vea qué tipo de resultados obtiene.

9

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

+1

El problema es que esto es solo después de que intenta asignar algo. Si se encuentra en una situación en la que "sabe" que tiene un diseño de memoria muy desorganizado y "sabe" que está a punto de requerir un gran bloque de memoria, puede invocar algunas instrucciones antes del GC. –

+2

Nunca "sabes" con certeza que tienes un diseño de memoria desorganizado. El GC podría haber corrido, por lo que sabes. La parte de "marca" de marcar y arrastrar requiere recursos y tiempo, incluso si no recopila nada.Es por eso que casi siempre es un caso de punto de equilibrio neto o (mejor caso) punto de equilibrio para intentar y ser más astuto que el GC. – Jason

+0

El tiempo de ejecución y el gc son libres de cambiar y moverse alrededor de los objetos en la memoria cuando le apetezca (los objetos son más como un puntero a un puntero si vienes del mundo C), casi nunca "sabrás" que tienes un diseño desorganizado – nos

1

Normalmente, 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.

Independientemente, si solo lo hace una vez, es probable que no afecte drásticamente su rendimiento. Las cosas hechas en bucles son mucho más importantes.

1

Ya tienes un montón de buenos consejos, que voy a tratar de no repetir.

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.

1

Asegúrese de que los objetos grandes se puedan conectar lo antes posible. Es decir. establecer las variables a nulo y/o dejarlas fuera del alcance. ¡Esto ayuda!

0

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).

1

Si falla la asignación de memoria, se inicia un ciclo de GC y se intenta nuevamente la asignación.

Cuestiones relacionadas