On Nov 1, 2013, at 6:23 AM, Scott Severtson <ssevert...@digitalmeasures.com> 
wrote:

> All,
> 
> We've noticed that our Tomcat 6.0.37 instances have increasing overhead the 
> longer they stay up. We've captured some heap dumps, expecting to find memory 
> leaks within our code, but found something different instead.
> 
> Jasper's BodyContentImpl is actually holding most of the non-collectible 
> garbage, in the internal char[] buffer. I've checked trunk of Tomcat 6, 7 and 
> 8, and see that the same implementation is still used, so this issue applies 
> to all currently supported versions.
> 
> This issue appears to be well known:
> * 
> http://stackoverflow.com/questions/10421908/is-there-a-fix-for-bodycontentimpl-jsp-tag-memory-leak-using-tomcat
> * https://issues.apache.org/bugzilla/show_bug.cgi?id=43925
> 
> Specifically what we see happening is due to large pages being rendered in 
> JSPs - sometimes in the multi-megabyte range, especially for internal tools. 
> Apparently, some of the tags we use require buffering the output, versus 
> sending it directly to the Writer.
> 
> Now, we certainly can simply set LIMIT_BUFFER and forget about it (throw away 
> any buffers larger than 8k), but this isn't optimal for our application. For 
> about 75% of our requests, ~8k is the baseline page size, with many larger 
> than that. So, depending how the data size, we could be reallocating multiple 
> times, only to throw away the buffer at the end.
> 
> We'd like to propose a different behavior, and are wondering what others 
> think about it. If it sounds like a good idea, we're certainly willing to 
> submit patches to implement it.
> 
> --Proposal--
> Instead of a hard-coded DEFAULT_TAG_BUFFER_SIZE of 8k, make it configurable. 
> In addition, if LIMIT_BUFFER is set, provide another configurable setting 
> called something like MAX_TAG_BUFFER_SIZE (if not set, defaults to 
> DEFAULT_TAG_BUFFER_SIZE). This would give applications a more predictable 
> *range* of memory allocated for tag buffers, while decreasing the frequency 
> of reallocation.
> --/Proposal--

Allowing for a cap on growth and throwing an IOException when it is hit seems 
like a reasonable precaution to prevent more drastic OOM errors (I've been 
bitten by this too).

Using a threshold rather than simple boolean to control recycling could be 
helpful. It could easily mimic the current functionality albeit at the cost of 
backward compatibility. However, I would expect see allocations gradually creep 
up to this limit across the board so it seems more predictable just to raise 
the default to that value.

> We'd probably set DEFAULT_TAG_BUFFER_SIZE to 16k, and set MAX_TAG_BUFFER_SIZE 
> to either 64k or 128k, based on real-world performance testing.

DEFAULT_TAG_BUFFER_SIZE is only 512 bytes and, AIUI, is set low-ish just to 
cover the common case where fragments generate small amounts of output. I don't 
think we should change the defaults for these.

> One other, slightly less defined question - is there a reason we're managing 
> char arrays ourselves, instead of using something like Java's StringBuilder 
> or Javalution's TextBuilder? StringBuilder would reduce code maintenance, 
> while something like TextBuilder would also reduce array allocation.

Patches are always welcome.

Cheers
Jeremy

Attachment: signature.asc
Description: Message signed with OpenPGP using GPGMail

Reply via email to