memory leak happens under stress when CPortletAdapter portlets are asked to clean themselves up when the session ends.
It looks like when the PortletStateManager is asked to clear the window state for a particular session, that session cannot be obtained due to the response already being committed. And since this exception is thrown, the subsequent cleaning of the static channelStateMap Map does not happen, which results in a memory leak.
Following is the error message
ERROR [http-8080-Processor128] portal.ChannelManager.[] Jan/20 22:12:53 -
Error sending session done event to channel
org.jasig.portal.MultithreadedPrivilegedCacheableDirectResponseCharacterChan
nelAdapter@1f91311
java.lang.IllegalStateException: Cannot create a session after the response
has been committed
at
org.apache.coyote.tomcat5.CoyoteRequest.doGetSession(CoyoteRequest.java:2270
)
at
org.apache.coyote.tomcat5.CoyoteRequest.getSession(CoyoteRequest.java:2116)
at
org.apache.coyote.tomcat5.CoyoteRequestFacade.getSession(CoyoteRequestFacade
.java:526)
at
org.apache.coyote.tomcat5.CoyoteRequestFacade.getSession(CoyoteRequestFacade
.java:531)
at
javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWr
apper.java:223)
at
org.jasig.portal.container.services.information.PortletStateManager.clearSta
te(PortletStateManager.java:370)
at
org.jasig.portal.channels.portlet.CPortletAdapter.receiveEvent(CPortletAdapt
er.java:342)
at
org.jasig.portal.MultithreadedCharacterChannelAdapter.receiveEvent(Multithre
adedCharacterChannelAdapter.java:62)
at
org.jasig.portal.ChannelManager.finishedSession(ChannelManager.java:269)
at
org.jasig.portal.UserInstance.valueUnbound(UserInstance.java:676)
at
org.apache.catalina.session.StandardSession.removeAttributeInternal(Standard
Session.java:1566)
at
org.apache.catalina.session.StandardSession.expire(StandardSession.java:708)
at
org.apache.catalina.session.StandardSession.expire(StandardSession.java:632)
at
org.apache.catalina.session.StandardSession.invalidate(StandardSession.java:
1051)
at
org.apache.catalina.session.StandardSessionFacade.invalidate(StandardSession
Facade.java:149)
at org.jasig.portal.LogoutServlet.doGet(LogoutServlet.java:142)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:689)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(Application
FilterChain.java:237)
at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterCh
ain.java:157)
at
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.ja
va:214)
at
org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContex
t.java:104)
at
org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at
org.apache.catalina.core.StandardContextValve.invokeInternal(StandardContext
Valve.java:198)
at
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.ja
va:152)
at
org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContex
t.java:104)
at
org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:137
)
at
org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContex
t.java:104)
at
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117
)
at
org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContex
t.java:102)
at
org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java
:109)
at
org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContex
t.java:104)
at
org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at
org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:929)
at
org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:160)
at
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:799)
at
org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConne
ction(Http11Protocol.java:705)
at
org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:577)
at
org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.jav
a:683)
at java.lang.Thread.run(Thread.java:534)
https://list.unm.edu/cgi-bin/wa?A2=ind0501&L=JASIG-DEV&D=0&I=-3&X=1F69E27727003AA020&Y=faizan%40rutgers.edu&P=6352
Ken/Eric,
Well, the problem is that under stress there seems to be a memory leak that
happens when CPortletAdapter portlets are asked to clean themselves up when
the session ends.
PortletStateManager.clearState(pcs.getHttpServletRequest()); throws an
exception when trying to create the session because the response has
already been committed. It probably shouldn't be trying to create the
session, but that's a separate matter...
We tried changing PortletStateManager and CPortletAdapter to use the
PortletWindow's ID (which gets initialized in CPortletAdapter to be session
dependent – sessionID+subscribedId) to store window states and it seems to
function correctly and does resolve the leak. As we're not entirely familiar
with this code and the motivations behind some of the implementation
decisions, I'd like to get your thoughts on the change and what impacts it
might have that we're not realizing.
I've attached the two source files which are based on up2.4.1.
Thanks!
-nick
Nick,
I'm not quite understanding why the channel subscribe ID is causing
problems when used as the PortletWindow ID. Could you explain a little
more? I am copying Eric on this because he may know what you're talking
about.
-Ken
nbolton wrote:
> Ken,
>
> (this is in reference to the "CPortletAdapter cleaning up causes memory
> leak" post I made last week)
>
> I noticed that in CPortletAdapter we initialize PortletWindow's identifier
> with the channel subscribe id. I thought the PortletWindow is supposed to
> have instance scope. Maybe that is why the portlet windows are also
managed
> using the session id. Couldn't we just make the portlet window id
something
> similar to the multithreaded uid's and get rid of the session id based
> management? Maybe I'm missing something here. Thoughts?
>
> -nick