[
https://issues.apache.org/struts/browse/WW-2167?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=43165#action_43165
]
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
http://jira.opensymphony.com/browse/XW-560. 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 block.
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
http://opensource.atlassian.com/confluence/spring/pages/viewpage.action?pageId=2669
for more possibilities if they are still having problems.
> Memory leak when app stopped
> ----------------------------
>
> Key: WW-2167
> URL: https://issues.apache.org/struts/browse/WW-2167
> Project: Struts 2
> Issue Type: Bug
> Affects Versions: 2.0.9
> Environment: WebSphere 6.1.0.9 (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 enabled)
> 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.