Richard (and Ben),

Appears like a lot of good work has gone into trying to resolve / fix this....

Thanks for the info.  I hope my comments in-line can assist....

--Nikolaos


Richard Hauswald wrote:
I spent some time investigating the problem - results:
Can you provide a little more information on the test system... OS and version, JDK version, web container and version,...

Can you provide the complete list of JVM options you use? I'm curious to see your heap settings, gc algorithm and options, gc ratios, thread stack size, etc... If you are using tomcat then simply have it echo the command it uses to launch the JVM....

Also have you tried enabling gc logging so that you can see when the minor and major gc's occur i.e. logging how the GC behaves as you run your test is typically enlightening, i.e. is it new generation or old generation objects that are growing, etc...
-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps

Also have you tried running with jconsole (its an Agent that gets added a JVM param on web container startup) to better analyze what objects are being retained and by what?

- The problem is not related to thread locals.
OK

- The memory costs using layout tag with ~2MB sized pages is
significant. Without layout tag the test (20 threads parallel same
page) took around 35MB, with layout tag around 190MB
That is significant. It would be interesting to repeat the test with small pages e.g. 50K or whatever to see if the issue still appears in the same proportion.

ASIDE:: JSPs use by default an 8K buffer IIRC to hold the page contents before returning it.... although upping this buffer dramatically is not recommended, as your pages are huge using a 32K or 64K buffer on a page will mean less flushes so it might improve your 2MB page regardless of this issue... of course it increases the delay in getting the data to the web browser... but it might be worth trying...

- After this test has passed the memory usage did not drop below 100MB
using stripes layout, without layout tag it did not drop under 10MB
This would appear to rule out the container / buffers not releasing memory... i.e. all things equal and merely interpreting your results only... this would point to something in the Stripes layout tag is not releasing memory...

(after requesting gc multiple times)
I assume this is by doing a "System.gc()"? Keep in mind that this can be totally ignored by the GC i.e. that the call is a "hint" or "can you please collect the garbage when you get a chance" upon which the GC can totally ignore the request, act on it later, etc... i.e. don't rely or expect that this will make any difference....

- The app crashed with heap space exceptions when running with 100MB
max heap and stripes layout tag. It did not without stripes layout
tag.
Well that is good in a way that you can get it to fall over. There are several things here:

1) Out of memory comes in various flavours (i.e. it could be related to java heap, perm gen which for most jvm's is OUTSIDE the java heap, etc...) can you provide a copy of the out of memory stack trace?

2) If the jvm crashed with out of memory exception then there should be a hs_err_pid<pid>.log or similar file in your working directory. This file will among other things will show what the state of the GC was at before running out of memory. Can you please provide this file from your crashed run.

3) I think you mentioned that you had a heap dump if so I assume you used: -XX:-HeapDumpOnOutOfMemoryError If so and you have a heap dump what are the top 50 or so objects by total size, total count, etc...?

It is important to state that the app crashed after 40 requests.
So the memory got filled up with each request.
If that truly was true then the long running test would consume tons of memory and eventually crash too... but it didn't which doesn't mean memory isn't increasing with each request but instead it means to me that memory increases to a certain threshold... and the 40 requests just got it to that point...

- I ran a test using stripes layout tag with 2 threads running request
after request for over 25 hours and the app is not leaking. The memory
usage did not drop below 100MB (after requesting gc multiple times).

Conclusion
There is no memory leak is stripes layout tag (currently ;-P )
I guess that depends on how you define a memory leak A memory leak does not have to leak like an oil well IMO. There is a difference of 90MB of data that is being retained based on your results and by what appears to be the Stripes layout tag... .

I wish Java came up with a different term and didn't borrow memory leak from say C/C++... because in Java a memory leak in my opinion is simply retaining references to objects that are no longer being used... just because this doesn't grow in size doesn't mean it isn't a memory leak... it could merely mean that the components that are holding the data beyond its useful life are simply swapping in new equally sized chunks of data that come in on the next request or whatever....

So to say that the Stripes framework layout tag is not leaking memory is not something I would agree with... if it doesn't release the increased memory it uses and is doing nothing with what it is retaining then it is a memory leak AFAIK.

There are still open questions:
- Why is the memory not released by gc after a request is finished
Remember GC and request processing are unrelated. When an object has zero references it is a candidate for GC. Just because the request has completed does not mean the GC will kick in and clean it up. GC depends highly on the algorithm used and other inner workings that unless your a VM engineer we need not worry or concern ourselves with i.e. IMO best to consider GC a black box that will do its thing when it wants to based on how you told it you wanted it to do it but with no guarantees on when / what gets done.

The only thing we should concern ourselves is with is WHAT is holding on to that data that is not getting GC'd (and what that data is).

- Why is the memory not released by gc after a request is finished is
increasing until reaching some magic random numbers around 100MB
Well it appears that... that Stripes layout tag is retaining something like data related to the last request OR X requests or whatever....

What happens if you run this ONE test while having gc logging enabled...
1) Do your 2MB Stripes layout requests steady for say 1 hour....
2) Then without restart do a 1MB Stripes layout requests steady for say 1 hour....

What is your memory at the end of 1) and at the end of 2)? Is it still 100MB or is it 50MB or something else?

- Can this behavior be reproduced in other containers eg. Jetty?
If you provide the 2 test cases I can try it on glassfish v3 final...

I think it is related to the tomcat buffer, the limit buffer = true
setting and that stripes layout tag is somehow referencing/using this
buffer.
If the Stripes layout tag is somehow still referencing or using the tomcat buffer then it is a Stripes memory leak. No?


Some other things to help with debugging this:
- http://happygiraffe.net/blog/2009/04/02/heap-dump-analysis/
- http://java.sun.com/j2se/1.5/pdf/jdk50_ts_guide.pdf
--> Great read but also try something called: jconsole and jmap -histo - http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp#DebuggingOptions


I would personally like to see this issue solved and will help as much as I can.

Thanks for the work you have done to date!

--Nikolaos

Many thanks to Ben,
Richard



On Wed, May 12, 2010 at 10:27 AM, M.C.S. <m...@syn-online.de> wrote:
Hi Ben,

could you please check in the patch into the 1.5.x and, if needed, the
1.4.x branches? Currently we are not using the version on trunk, but
also would like to benefit from the fix asap.

Marcus


Am 11.05.2010 17:10, schrieb Ben Gunter:
I did a little poking around and found that sometime in 2008,
LayoutComponentTag was changed such that it does not null its
reference to its BodyContent. Apparently it had to do with a bug in
Resin, but I suspect it might have led to a memory leak. The JSP spec
is clear that setBodyContent is to be called after each call to
doStartTag() that returns EVAL_BODY_BUFFERED so there's no reason to
retain a reference to the BodyContent. I've reverted that change in
the trunk. Can you check out and build the trunk and see if that helps
the memory issues?

-Ben
------------------------------------------------------------------------------

_______________________________________________
Stripes-users mailing list
Stripes-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/stripes-users




------------------------------------------------------------------------------

_______________________________________________
Stripes-users mailing list
Stripes-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/stripes-users

Reply via email to