users@glassfish.java.net

[gf-users] JSP Tag Pooling "memory leak" GF 3.1.2

From: Will Hartung <willh_at_mirthcorp.com>
Date: Tue, 4 Aug 2015 10:04:52 -0700

Running GF 3.1.2.

We were having a strange memory leak problem that we were trying to track down, and it looks like it's ending up rooted in JSP tag pooling.

We kept finding growing counts of objects, and could not find anything glaring in our own code. But it was clear that count was growing.

After some digging with jmap and jhat, we found that these objects were being held on to by JSP tag instances. Having encountered some issues with JSP Tag Pooling in the past, I at least was aware that the concept existed.

Digging some more, I found the jsp-config property enablePooling, which I set to false in my glassfish-web.xml.

But, I still found the leak.

Tearing in to the source code, I found a couple of interesting things.

When you look at the source of a JSP generated file you see things like:

    org.apache.taglibs.standard.tag.rt.core.ForEachTag _jspx_th_c_forEach_0 = (_jspx_resourceInjector != null) ? _jspx_resourceInjector.createTagHandlerInstance(org.apache.taglibs.standard.tag.rt.core.ForEachTag.class) : new org.apache.taglibs.standard.tag.rt.core.ForEachTag();

When I searched for what "enablePooling" seemed to affect, it looked to be tied to the JSP compiler. Yet, the generated java code continued to create lines like the above regardless of the setting.

We also find code like this at the top of the generated JSP code:

      _jspx_resourceInjector = (org.glassfish.jsp.api.ResourceInjector) application.getAttribute("com.sun.appserv.jsp.resource.injector");

Looking some more, I could not find the JSP compiler source code used by GF3. It seemed to rely Apache's Jasper compiler, which is well and good. But Apache does not distribute Jasper separately from Tomcat. You can't just plonk a maven dependency in your project and get the Jasper JspC compiler.

Yet, there is clearly GF specific code in the JSPs. So I don't know what code is used to create the GF specific JSPs. In fact, there are no references to "com.sun.appserv.jsp.resource.injector" anywhere in the GF source code except where the attribute is set by the runtime. And that attribute is always set by the runtime, completely ignoring the state of the "enablePooling" jsp-config property.

In the end, our tentative fix that we're testing is to simply reset the "com.sun.appserv.jsp.resource.injector" property in the ServletContext during web app startup. Setting it to null forces the JSPs to simply create new tag instances every time, for good or ill.

        getServletContext().setAttribute("com.sun.appserv.jsp.resource.injector", null);

One of the things were doing, is that we're sending large lists to tags such as <c:foreach>, and those lists are captured by the underlying tag object, and thus retained.

I have not looked at the ResourceInjectorImpl to determine how many of what it caches for how long or how the instances are reused. In our case it captures "too much" and holds it for "too long". Granted, we are sending it large lists of data. But that should be "ok". Lots of examples of large reports done in JSPs.

Fundamentally, is that we appear to have an opaque cache here, that we can not (elegantly) disable.

I'll be digging deeper in the ResourceInjectorImpl just to see what it's behavior is, but figured I'd share what I found here for posterity. But I am curious where the JSP compiler is.

Regards,

Will Hartung
(willh_at_mirthcorp.com)




-- 
This message, and any documents attached hereto, may contain confidential 
or proprietary information intended only for the use of the addressee(s) 
named above or may contain information that is legally  privileged. If you 
are not the intended addressee, or the person responsible for delivering it 
to the intended addressee, you are hereby notified that reading, 
disseminating, distributing or copying this message is strictly prohibited. 
If you have received this message by mistake, please immediately notify us 
by replying to the message and delete the original message and any copies 
immediately thereafter.  Thank you for your cooperation.