struts-issues mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Sean Kleinjung (JIRA)" <>
Subject [jira] Commented: (WW-2167) Memory leak when app stopped
Date Fri, 08 Feb 2008 01:26:40 GMT


Sean Kleinjung commented on WW-2167:

Ok.. My previous comment was made a bit prematurely. Call me an optimist. It looks like there
are actually three places where references are being kept and causing classloader leaks --
all related to XWork ThreadLocals.

1. The InternalContext leak referenced by I previously
stated this was resolved in version 2.1.0 of XWork, but upon closer inspection the patch was
not fully applied. Applying the patch attached to that Jira issue WILL resolve this leak,
but it is not yet fixed in the xwork trunk.

2. The Struts FilterDispatcher's init method results in an ActionContext being stored in a
ThreadLocal that is never cleaned up. This is because it calls "Dispatcher.init()" which eventually
results in a call to org.apache.struts2.config.StrutsXmlConfigurationProvider.loadPackages.
This method calls ActionContext.getContext(), which attempts to access the ActionContext stored
in a ThreadLocal. If there is none, one is created via the com.opensymphony.xwork2.ActionContext.ActionContextThreadLocal.initialValue
method. This instance is not cleaned up anywhere by Struts or xwork. I am not certain who
is responsible for cleaning up this 'default' ActionContext, so I cannot say for certain if
this is a bug in Struts or xwork. However, it can be fixed by wrapping the init method of
FilterDispatcher in a try block, and calling ActionContext.setContext(null) in the finally

3. The Struts FilterDispatcher's destroy method has a similar problem to #2, except this time
the offending ActionContext is ultimately created from a call in org.apache.struts2.config.StrutsXmlConfigurationProvider.needsReload.
This leak can also be fixed by wrapping the destroy method in a try block and clearing the
ActionContext in its finally.

It is worth noting that in 2.1.0 and beyond of xwork, there is no initialValue implementation
for the ActionContext thread local. I haven't looked at the xwork source closely enough to
know if they are manually creating (and hopefully destroying) an ActionContext in cases that
were previously handled by initialValue. If they are not, however, then the calls from init
and destroy above will receive a null ActionContext, and need to change accordingly.

So, to summarize there are two things that must happen in order for a Struts app to undeploy
cleanly without classloader leaks:
1) The XW-560 issue must be resolved
2) The lifecycle methods on FilterDispatcher must properly clean up their ActionContext thread
locals. This could probably be done by a change to xwork, but in the meantime a patch to FilterDispatcher
can accomplish the same thing. I am attaching a patched version of FilterDispatcher that my
testing has found to be leak-free.

Now, even after the above is done there are a lot of other, non-Struts, leak culprits. I would
advise any interested persons to read
for more possibilities if they are still having problems.

> Memory leak when app stopped
> ----------------------------
>                 Key: WW-2167
>                 URL:
>             Project: Struts 2
>          Issue Type: Bug
>    Affects Versions: 2.0.9
>         Environment: WebSphere (non-network deploy) on Windows XP Professional
> java version "1.5.0"
> Java(TM) 2 Runtime Environment, Standard Edition (build pwi32devifx-20070608 (SR5+IY99712))
> IBM J9 VM (build 2.3, J2RE 1.5.0 IBM J9 2.3 Windows XP x86-32 j9vmwi3223-20070426 (JIT
> J9VM - 20070420_12448_lHdSMR
> JIT  - 20070419_1806_r8
> GC   - 200704_19)
> JCL  - 20070608
>            Reporter: Adam Crume
>             Fix For: 2.1.2
>         Attachments: log_leak.png
> Struts 2 somehow prevents the app's classes from being garbage collected when the application
is stopped or undeployed.
> I created a barebones Struts 2 app with an action with the following code:
> 	private static final Object x = new Object() {
> 		{
> 			System.out.println("================== Object created: " + hashCode() + " ===================");
> 		}
> 		protected void finalize() throws Throwable {
> 			System.out.println("**************** Object finalized: " + hashCode() + " *********************");
> 		};
> 	};
> Because of this static field, a message should be printed when the class is initialized
and when it is garbage collected.  "Object created" would be printed out whenever I went to
the action for the first time, but restarting the app never printed "Object finalized."  This
is not an issue with garbage collection in my web container because doing the same thing with
a servlet resulted in both messages being printed.
> One problem is that the FilterDispatcher.init() method sets a ThreadLocal but never clears
it.  I fixed that by adding ActionContext.setContext(null); to the end of the init() method,
but that didn't solve the larger problem.

This message is automatically generated by JIRA.
You can reply to this email to add a comment to the issue online.

View raw message