[#4768] - Possible memory leak in JasperReports 3.7.3 when restarting/redeploying a web application

Category:
Bug report
Priority:
High
Status:
Acknowledged
Project: Severity:
Critical
Resolution:
Open
Component: Reproducibility:
Always
Assigned to:

Dear developers,

We have developed a web application which uses JasperReports 3.7.3.

We use Tomcat 6.0.26 as a container. (Win XP, JDK 1.6.0_10)

We shutted down Tomcat, and we found the following messages in the catalina.log file:

SEVERE: A web application created a ThreadLocal with key of type [null] (value [net.sf.jasperreports.engine.util.JRFontUtil$1@19d373]) and a value of type [java.util.HashSet] (value ) but failed to remove it when the web application was stopped. To prevent a memory leak, the ThreadLocal has been forcibly removed.

It seems to be a leak.

AttachmentSize
File JRFontUtil.java.diff983 bytes
lacito's picture
157
Joined: Apr 8 2009 - 3:14am
Last seen: 9 years 5 months ago

10 Comments:

#1

This is blocker for using JasperReports in JBoss and other containers which uses hot redeploy. So I have changed the severity to critical.

Please, use ThreadLocal sparingly and with a big care. Take a look at http://xmedeko.blogspot.com/2010/02/java-web-container-hunting-redeploy..... This bug is caused particularly by static ThreadLocal inner class, see http://crazybob.org/2006/02/threadlocal-memory-leak.html.

This bug can be easily solved (I'll post the fix later).

But I mean, the ThreadLocal in the JRFontUtil has a functionality just to limit number of WARN logs - in my opinion, it would be best to remove the ThreadLocal from this class completely. Why?
1. It does not improve any functionality, just causes problems
2. Some web servers, like Tomcat, use thread pool. So, if you do not clean the ThreadLocal after the request finishes, then the HashSet with missing fonts will occupy the memory forever (until the web server shut downs). E.g. if the pool has 300 threads and the JRFontUtil.threadMissingFontsCache occupy 1kB, then after some time the 300kB of memory is wasted.

#2

BTW. may static ConcurrentHashMap do the job? As a value, put Boolean.TRUE. It should not leak, I hope.

#3

Please fix this.

#4
  • Assigned:teodord» lucianc
#5

Has anyone managed to fix this problem yet? This bug report is 3 years old and still opened. I've just inspected JRFontUtil.java (iReport 5.1.0) and there's no trace of the pdiff attached to this bug report. Does this mean that JasperRerports Library 5.1.0 is still affected by this memory leak problem? I'm using 3.7.3 and having these memory leak problems when stopping Tomcat 6.0.33:

GRAVE: The web application [] created a ThreadLocal with key of type [net.sf.jasperreports.engine.util.JRFontUtil$1] (value [net.sf.jasperreports.engine.util.JRFontUtil$1@51593a58]) and a value of type [java.util.HashSet] (value ) but failed to remove it when the web application was stopped. This is very likely to create a memory leak.

These leaks are causing an excessive number of hanging threads.

#6

Hello,
as stated in http://community.jaspersoft.com/jasperreports-library/issues/4882, we also ran into permgen oom after hot deployment.
It would be great if you would include the fix, as there does not seem to be a workaround available.

Best regards
Darius

#7
  • Priority:Low» High

This problem is known from years ago, Respectfully I can say it's just a shame that to this time (2014) stills with no solution. In my Tomcat 7.0.47 JasperReports 5.5.2 it generates a couple of Classloader leaks when the application is redeployed or undeployed, I can say that this problem is originated by the use of ThreadLocals that never get cleared properly, for example the class FontUtil (see http://grepcode.com/file/repo1.maven.org/maven2/net.sf.jasperreports/jas...) you can see the use of ThreadLocal.
I verified taking a heap dump that the cause of the classloader leaks is the ThreadLocals started by JasperReports.

It's known that ThreadLocals must be cleared somehow, So Why not create a class to clear that ThreadLocals and instruct the users of JasperReports to use that class in a ServletContextListener when the application is destroyed, for example years ago the MySQL driver had the same problem and they fixed in a clever way (http://bugs.mysql.com/bug.php?id=65909)

It could be something like:

@WebListener //ServletContextListener created by the user
public class ClearThreadsJPListener implements ServletContextListener {
public void contextDestroyed(ServletContextEvent arg0) {
try {
//This is the new class that you could provide
ClearThreadLocalsJasperReports.clearEverything();
} catch (InterruptedException e) {
}
}

}

Here the logs of my Tomcat
INFORMACIÓN: Repliegue (undeploy) de la aplicación web que tiene como trayectoria de contexto /dmsso##000110
sep 06, 2014 2:33:37 PM org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks
GRAVE: La aplicación web [/dmsso##000110] creó un ThreadLocal con clave del tipo [java.lang.ThreadLocal] (valor [java.lang.ThreadLocal@1af7349]) y un valor del tipo [java.lang.Class] (valor [class reporteAnexo7CFinal_dsDiagnosticosFichaInfComp_1409869112590_774432]) pero no pudo quitarlo cuando la aplicación web se paró. Los hilos se van a renovar con el tiempo para intentar evitar in posible fallo de memoria.
sep 06, 2014 2:33:37 PM org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks
GRAVE: La aplicación web [/dmsso##000110] creó un ThreadLocal con clave del tipo [net.sf.jasperreports.engine.fonts.FontUtil$1] (valor [net.sf.jasperreports.engine.fonts.FontUtil$1@275cc5]) y un valor del tipo [java.util.HashSet] (valor ) pero no pudo quitarlo cuando la aplicación web se paró. Los hilos se van a renovar con el tiempo para intentar evitar in posible fallo de memoria.
sep 06, 2014 2:33:37 PM org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks
GRAVE: La aplicación web [/dmsso##000110] creó un ThreadLocal con clave del tipo [java.lang.ThreadLocal] (valor [java.lang.ThreadLocal@1af7349]) y un valor del tipo [java.lang.Class] (valor [class reporteAnexo7CFinal_dsDiagnosticosFichaInfComp_1409869112590_774432]) pero no pudo quitarlo cuando la aplicación web se paró. Los hilos se van a renovar con el tiempo para intentar evitar in posible fallo de memoria.
sep 06, 2014 2:33:37 PM org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks
GRAVE: La aplicación web [/dmsso##000110] creó un ThreadLocal con clave del tipo [net.sf.jasperreports.engine.fonts.FontUtil$1] (valor [net.sf.jasperreports.engine.fonts.FontUtil$1@275cc5]) y un valor del tipo [java.util.HashSet] (valor ) pero no pudo quitarlo cuando la aplicación web se paró. Los hilos se van a renovar con el tiempo para intentar evitar in posible fallo de memoria.
sep 06, 2014 2:33:37 PM org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks
GRAVE: La aplicación web [/dmsso##000110] creó un ThreadLocal con clave del tipo [java.lang.ThreadLocal] (valor [java.lang.ThreadLocal@1af7349]) y un valor del tipo [java.lang.Class] (valor [class reporteAnexo7CFinal_dsDiagnosticosFichaInfComp_1409869112590_774432]) pero no pudo quitarlo cuando la aplicación web se paró. Los hilos se van a renovar con el tiempo para intentar evitar in posible fallo de memoria.
sep 06, 2014 2:33:37 PM org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks
GRAVE: La aplicación web [/dmsso##000110] creó un ThreadLocal con clave del tipo [net.sf.jasperreports.engine.fonts.FontUtil$1] (valor [net.sf.jasperreports.engine.fonts.FontUtil$1@275cc5]) y un valor del tipo [java.util.HashSet] (valor ) pero no pudo quitarlo cuando la aplicación web se paró. Los hilos se van a renovar con el tiempo para intentar evitar in posible fallo de memoria.
sep 06, 2014 2:33:37 PM org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks
GRAVE: La aplicación web [/dmsso##000110] creó un ThreadLocal con clave del tipo [java.lang.ThreadLocal] (valor [java.lang.ThreadLocal@1af7349]) y un valor del tipo [java.lang.Class] (valor [class reporteAnexo7CFinal_dsDiagnosticosFichaInfComp_1409869112590_774432]) pero no pudo quitarlo cuando la aplicación web se paró. Los hilos se van a renovar con el tiempo para intentar evitar in posible fallo de memoria.
sep 06, 2014 2:33:37 PM org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks
GRAVE: La aplicación web [/dmsso##000110] creó un ThreadLocal con clave del tipo [net.sf.jasperreports.engine.fonts.FontUtil$1] (valor [net.sf.jasperreports.engine.fonts.FontUtil$1@275cc5]) y un valor del tipo [java.util.HashSet] (valor ) pero no pudo quitarlo cuando la aplicación web se paró. Los hilos se van a renovar con el tiempo para intentar evitar in posible fallo de memoria.
sep 06, 2014 2:33:37 PM org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks
GRAVE: La aplicación web [/dmsso##000110] creó un ThreadLocal con clave del tipo [java.lang.ThreadLocal] (valor [java.lang.ThreadLocal@1af7349]) y un valor del tipo [java.lang.Class] (valor [class reporteAnexo7CFinal_dsDiagnosticosFichaInfComp_1409869112590_774432]) pero no pudo quitarlo cuando la aplicación web se paró. Los hilos se van a renovar con el tiempo para intentar evitar in posible fallo de memoria.
sep 06, 2014 2:33:37 PM org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks
GRAVE: La aplicación web [/dmsso##000110] creó un ThreadLocal con clave del tipo [net.sf.jasperreports.engine.fonts.FontUtil$1] (valor [net.sf.jasperreports.engine.fonts.FontUtil$1@275cc5]) y un valor del tipo [java.util.HashSet] (valor ) pero no pudo quitarlo cuando la aplicación web se paró. Los hilos se van a renovar con el tiempo para intentar evitar in posible fallo de memoria.

#8

This may not be directly related, but JDK1.6 is known to have memory leak problems. Try upgrading to JDK1.7.
Probably better to create a new issue with JasperReports 5.6.1 is the problem persists.

#9

Still present in v6.0.3. Please fix it.
The provided patch will not fix the problem.
Need to set the threadMissingFontsCache attribute to null.
Most likely in a ServletContextListener as suggested.
Using reflection, you can workaround the problem.
Call this method from contextDestroyed() of a ServletContextListener:

private void clearJasperLocalThread() {
try {
Field field = FontUtil.class.getDeclaredField("threadMissingFontsCache");
if (field != null) {
field.setAccessible(true);

Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

field.set(null, null);
}
} catch (IllegalAccessException | NoSuchFieldException | SecurityException ex) {
Logger.getLogger(BasewebContextListener.class.getName()).log(Level.SEVERE, null, ex);
}
}

#10

Still present in version 6.2.1

I see this error every time I use the jasper reports library to generate a report and then try to restart/redeploy my web application.

Feedback