[ 
https://issues.apache.org/jira/browse/DIRMINA-1086?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16502931#comment-16502931
 ] 

Wenxiang Qiu commented on DIRMINA-1086:
---------------------------------------

Hi Emmanuel,

Turns out I just didn't give ApacheDS the time to perform GC. No memory leak 
here with mina 2.0.17.

This test code does cause memory leak with mina 2.0.13. SelectionKey.valid is 
set to false with the following callstack:

AbstractSelectionKey#cancel()
NioProcessor#destroy()
AbstractPollingProcessor#writeBuffer()
AbstractPollingProcessor#flushNow()
AbstractPollingProcessor#flush()
AbstractPollingProcessor$Processor#run()

The reason it works fine with 2.0.17 is because a destroy() has been added to 
AbstractIoSession#closeNow() (called by filterChain.fireExceptionCaught(e)) 
which empties the session's writeRequestQueue and thus in 
AbstractPollingProcessor#flushNow(), writeBuffer() is not called.

I'll try to find out other ways that would invalid a session's SelectionKey 
before it gets removed.

 

> IoSessions closed by filterChain.fireExceptionCaught(e) are kept in memory
> --------------------------------------------------------------------------
>
>                 Key: DIRMINA-1086
>                 URL: https://issues.apache.org/jira/browse/DIRMINA-1086
>             Project: MINA
>          Issue Type: Bug
>          Components: Core
>    Affects Versions: 2.0.17
>         Environment: mina in ApacheDS
>            Reporter: Wenxiang Qiu
>            Priority: Major
>
> I'm using ApacheDS, I found this problem and am not sure if it's a mina issue 
> or an ApacheDS issue.
>  
> AbstractPollingIoProcessor#read looks like this:
>  
> {code:java}
> private void read(S session) {
>     IoSessionConfig config = session.getConfig();
>     int bufferSize = config.getReadBufferSize();
>     IoBuffer buf = IoBuffer.allocate(bufferSize);
>     final boolean hasFragmentation = 
> session.getTransportMetadata().hasFragmentation();
>     try {
>         /* omitted */
>         if (ret < 0) {
>             IoFilterChain filterChain = session.getFilterChain();
>             filterChain.fireInputClosed();
>         }
>     } catch (Exception e) {
>         if ((e instanceof IOException) &&
> (!(e instanceof PortUnreachableException)
> || !AbstractDatagramSessionConfig.class.isAssignableFrom(config.getClass())
> || ((AbstractDatagramSessionConfig) config).isCloseOnPortUnreachable())) {
>             scheduleRemove(session);
>         }
>         IoFilterChain filterChain = session.getFilterChain();
>         filterChain.fireExceptionCaught(e);
>     }
> }
> {code}
>  
> When an exception occurs with an LDAP connection, e.g. Connection reset by 
> peer, catch block is entered and ExcpetionCaught gets fired:
> {code:java}
> filterChain.fireExceptionCaught(e);{code}
> The session is thus closed by LdapProtocolHandler#exceptionCaught:
> {code:java}
> public void exceptionCaught( IoSession session, Throwable cause )
> {
>     if ( cause.getCause() instanceof ResponseCarryingMessageException )
>     {
>         ResponseCarryingMessageException rcme = ( 
> ResponseCarryingMessageException ) cause.getCause();
>         if ( rcme.getResponse() != null )
>         {
>             session.write( rcme.getResponse() );
>             return;
>         }
>     }
>     LOG.warn( "Unexpected exception forcing session to close: sending 
> disconnect notice to client.", cause );
>     session.write( NoticeOfDisconnect.PROTOCOLERROR );
>     LdapSession ldapSession = 
> this.ldapServer.getLdapSessionManager().removeLdapSession( session );
>     cleanUpSession( ldapSession );
>     session.close( true );
> }
> {code}
> Although this session is scheduled for removal, due to its state being 
> closing, AbstractPollingIoProcessor#removeSessions does nothing about this 
> session:
> {code:java}
> case CLOSING:
>     // Skip if channel is already closed
>     // In any case, remove the session from the queue
>     removedSessions++;
>     break;
> {code}
> Consequence is that this session is kept forever in 
> IoServiceListenerSupport.managedSessions, and as its size grows, this 
> ConcurrentMap can take up quite a large amount of memory.



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to