[ 
https://issues.apache.org/jira/browse/CXF-2164?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12907265#action_12907265
 ] 

Mauro Molinari commented on CXF-2164:
-------------------------------------

I don't know if it's better to reopen this bug or to file a new one.
I still have problems with ThreadLocals not being released.

The problem is that cxf.xml declares the following bean:

<bean id="cxf" class="org.apache.cxf.bus.CXFBusImpl"/>

Here, the destroy-method is not declared. This means that when Sping shuts down 
the context, it does not call any shutdown method on the CXFBusImpl.

This has nothing to do with the init and destroy methods of the CXFServlet, 
which might occur in different threads. Moreover, I see the problem even if I 
don't start the CXFServlet at all (no load-on-startup).

The net result is the following:
- Tomcat starts
- Tomcat starts my web application
- this declares a Spring web application context that gets parsed
- at some point cxf.xml is parsed, so the bean named cxf is created and an 
org.apache.cxf.bus.CXFBusImpl instance is created using the constructor 
org.apache.cxf.bus.CXFBusImpl.CXFBusImpl(Map<Class, Object>), which causes the 
org.apache.cxf.BusFactory.localBus ThreadLocal to be assigned a value of this 
type, through a call to org.apache.cxf.BusFactory.possiblySetDefaultBus(Bus); I 
see that this happens in a thread called "main"
- if I stop the web application, Spring closes down the context; however, as I 
said before, this does not cause any shutdown method of the cxf bean to be 
called
- so there's no null-setting or removing operation of the 
org.apache.cxf.BusFactory.localBus ThreadLocal for the thread "main"

I think the easiest fix is to modify the cxf bean definition in this way:
<bean id="cxf" class="org.apache.cxf.bus.CXFBusImpl" destroy-method="shutdown"/>
However, org.apache.cxf.bus.CXFBusImpl.shutdown(boolean) should be refactored 
so that it does not take the boolean parameter (it's not used actually), 
otherwise an overloading of this method without parameters should be provided.

However, this will work with the assumption that the Spring context load and 
shutdown operations are both executed in the same thread. I don't know if this 
is guaranteed by the servlet specifications or not (I'm using the 
org.springframework.web.context.ContextLoaderListener servlet listener to 
handle the lifecycle of the webapp application context). A better fix could be 
to avoid to hold state information for the CXFBusImpl in this way (i.e.: why 
does a constructor set a ThreadLocal and leave it there???).

Please note I'm working with CXF 2.2.10.

> CXFBusImpl never removed from ThreadLocal, generates permgen out of memory 
> error after some redeployments
> ---------------------------------------------------------------------------------------------------------
>
>                 Key: CXF-2164
>                 URL: https://issues.apache.org/jira/browse/CXF-2164
>             Project: CXF
>          Issue Type: Bug
>          Components: Bus
>    Affects Versions: 2.1.4
>            Reporter: Francois Masurel
>            Assignee: Bharath Ganesh
>             Fix For: 2.2.2
>
>         Attachments: cxf_threadlocal.jpg, 
> Heap_Walker_Incoming_References.zip, threadlocal.patch
>
>
> I've found this message on a mailing list recently, and it doesn't seem to 
> have been resolved as we have the same problem with version 2.1.4 of CXF on 
> one of our webapp :
> Hello CXF users,
> I've been  working on figuring out why our JBoss servers keep going down with 
> permgen out
> of memory exceptions when we redeploy our war files. To do this I had been 
> using a profiler
> to inspect the WebAppClassloader to find out what was keeping it from being 
> garbage collected.
> One such culprit was the class org.apache.cxf.BusFactory
> The BusFactory has a ThreadLocal in which it stores a copy of CXFBusImpl. 
> However, this isn't
> getting cleaned up properly when the war is undeployed. I noticed that 
> CXFBusImpl has a shutdown
> method that calls BusFactory.setDefaultBus(null) which in turn sets the value 
> stored in the
> ThreadLocal to null. However, this doesn't seem to be getting called.
> The way we are using CXF from spring is with the following 
> WEB-INF/services.xml file in our
> war:
>   <beans xmlns="http://www.springframework.org/schema/beans"; 
> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
>     xmlns:amq="http://activemq.org/config/1.0"; 
> xmlns:jaxws="http://cxf.apache.org/jaxws";
>     xmlns:http-conf="http://cxf.apache.org/transports/http/configuration";
>     xsi:schemaLocation="
>       http://www.springframework.org/schema/beans 
> http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
>       http://cxf.apache.org/transports/http/configuration 
> http://cxf.apache.org/schemas/configuration/http-conf.xsd
>       http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
>       http://activemq.org/config/1.0 
> http://activemq.apache.org/schema/core/activemq-core-5.0.0.xsd";
>     default-autowire="byType">
>     <import resource="classpath:META-INF/cxf/cxf.xml" />
>     <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
>     <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
>     <jaxws:endpoint id="helloService" implementor="#helloSvc" 
> address="/HelloService" />
>   </beans>
> I'm not really sure why this Bus.shutdown() isn't getting called or even who 
> is responsible
> for calling it. I tried doing something along the lines of:
>   WebApplicationContext webContext = 
> WebApplicationContextUtils.getRequiredWebApplicationContext(context);
>   if (webContext.containsBean("cxf")) {
>     CXFBusImpl cxfBus = (CXFBusImpl) webContext.getBean("cxf");
>     cxfBus.shutdown(true);
>   }
> But that didn't work. What I eventually ended up doing was to have the 
> following hack in the
> shutdown sequence of our webapp:
>   Field field = org.apache.cxf.BussFactory.class.getDeclaredField("localBus");
>   field.setAccessible(true);
>   ThreadLocal<?> localBus = (ThreadLocal<?>) field.get(null);
>   localBus.remove();
> This did work but obviously it is a bit of an ugly hack. Is there something 
> that needs to
> be included in our service.xml file to tell spring how to cleanup CXF? Is 
> this maybe a bug
> in CXF that the CXFBusImpl.shutdown(Boolean) just isn't getting called at all 
> or maybe that
> in BusFactory.setThreadDefaultBus(Bus) that there should be some check such 
> as:
>   if (bus == null) {
>     localBus.remove();
>   } else {
>     localBus.set(bus);
>   }
> Or maybe some combination of all of these. I'm reasonably new to CXF, Spring, 
> and all this
> stuff so I apologize ahead of time if there is some obvious solution that I 
> just didn't come
> across but I've been trying to scour the CXF and Spring documentation for 
> some idea of the
> correct way to do this and why BusFactory is keeping its ThreadLocal but I 
> can't figure it
> out.
> Thanks!
> Ben Dean
> Software Engineer
> Ontario Systems, LLC

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

Reply via email to