Actualización Groovy que causa un montón de GroovyClassLoaders muertos en PermGen
Tengo un proyecto Java 7 que ejecuta scripts cada n minutos por n procesos. Aquí hay un ejemplo del código que ejecuta los scripts.
ScheduledFuture scheduledFuture = scheduledService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try (GroovyClassLoader cl = new GroovyClassLoader()) {
// Load up reusable script modules in the class loader
Class scriptClass = cl.parseClass(scriptSource);
Foo script = optimizationClass.newInstance();
// Tell Groovy that we don't need class meta info
GroovySystem.getMetaClassRegistry().removeMetaClass(scriptClass);
script.run();
cl.clearCache();
} catch (IOException e) {
LOGGER.error("Failed to cleanup Groovy class loader, this will cause a memory leak", e);
}
}
}, 0, scheduledRun, TimeUnit.SECONDS);
scheduledFuture.get();
Por alguna razón con Groovy 2.1.7 no hay pérdida de memoria en Perm Gen. Al actualizar a Groovy 2.3.8 o Groovy 2.2.0, Perm Gen sigue llenándose de cargadores de clase Groovy muertos.
0x000000071ada2cd0 33 488 160 0x000000071b2493c8 muertos maravilloso / lang / GroovyClassLoader $ InnerLoader @ 0x00000007c7b70ef8 0x00000007265883b8 33 488 160 0x0000000725837270 muertos maravilloso / lang / GroovyClassLoader $ InnerLoader @ 0x00000007c7b70ef8 0x00000007157b5da0 26 370 736 0x000000072326f468 org vivo / Codehaus / maravilloso / runtime / callsite / CallSiteClassLoader @ 0x00000007c831d388 0x000000071ada1fb0 32 423 944 0x000000071af03a98 muertos maravilloso / lang / GroovyClassLoader $ InnerLoader @ 0x00000007c7b70ef8 0x0000000719d605b0 32 456 520 0x000000071af04798 muertos maravilloso / lang / GroovyClassLoader $ InnerLoader @ 0x00000007c7b70ef8 0x0000000725b82500 0 0 0x000000072326f468 muertos maravilloso / lang / GroovyClassLoader @ 0x00000007c74c33e8 0x00000007263eef80 34 532 448 0x0000000726d5c678 muertos maravilloso / lang / GroovyClassLoader $ InnerLoader @ 0x00000007c7b70ef8 0x000000072687b3c8 33 485288 0x0000000726c36340 dead groovy / lang / GroovyClassLoader $ InnerLoader @ 0x00000007c7b70ef8 0x0000000725d56db0 33 485288 0x000000072607bcc0 dead groovyCoa / Lang / GroovyCoader / GroovyCoo der @ 0x00000007c7b70ef8
Espero hasta que ocurra un GC completo, pero parece que cualquier versión posterior a Groovy 2.2 ha estado causando que Perm Gen se llene. Revisé las notas de la versión entre la versión en la que estaba hasta la versión actualizada y no noté ningún cambio que pudiera desencadenar esto.
Revisé aquí por problemas similares e intenté algunas sugerencias pero no tuve suerte. ¿Alguna idea de la causa?
Actualizar:
Hice un Diff en GrepCode en GroovyClassLoader de 2.1.7 a 2.2.0 y no hubo cambios. También tomé un archivo de volcado de montón cuando la aplicación se estaba ejecutando y no había ninguna ruta a las raíces de GC para obtener referencias sólidas.
El problema parece estar por aquí:
Class scriptClass = cl.parseClass(scriptSource);
Foo script = scriptClass.newInstance();
Cuando no compilo el script, obtengo 0 Groovy ClassLoaders en Perm Gen. Cuando compilo el script pero no lo ejecuto, me muero Groovy ClassLoaders.
Actualizar:
Encontró el código que está causando la fuga.
Foo script = scriptClass.newInstance();
No estoy seguro de cómo solucionar esto, ya que necesito crear una nueva instancia para ejecutar el script.