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

jpalacios commented on SSHD-854:
--------------------------------

Hi [~elecharny],

Thank you for getting back to me.
{quote}First, check the logs you should see messages like ' Create a new 
selector. Selected is 0, delta = XXX'.
{quote}
Unfortunately this is not possible. Bitbucket Server sets logging of 
{{org.apache.mina.core.service.IoProcessor}} to {{ERROR}} so the messages will 
not be present. However in the heap dump I can see multiple 
{{SelectionKeyImpl}} instances referencing the same {{NioSocketSession}} 
instance. As I said, there are {{382976}} instances of {{SelectionKeyImpl}} and 
only 94026 {{NioSocketSession}} instances. Wouldn't you say that indicates that 
the selector is being replaced and new keys are being generated?
{quote}The new selector will just use the registered {{SelectionKey}} from the 
old selector
{quote}
Are you sure this is correct? AFAICT it isn't. {{NioProcessor}} will register 
the new instance of the selector with the channel and it will get a new key:
{code:java}
SelectionKey newKey = ch.register(newSelector, key.interestOps(), session);
{code}
This is the implementation of {{AbstractSelectableChannel.register}}:
{code:java}
    public final SelectionKey register(Selector sel, int ops,
                                       Object att)
        throws ClosedChannelException
    {
        synchronized (regLock) {
            if (!isOpen())
                throw new ClosedChannelException();
            if ((ops & ~validOps()) != 0)
                throw new IllegalArgumentException();
            if (blocking)
                throw new IllegalBlockingModeException();
            SelectionKey k = findKey(sel);
            if (k != null) {
                k.interestOps(ops);
                k.attach(att);
            }
            if (k == null) {
                // New registration
                synchronized (keyLock) {
                    if (!isOpen())
                        throw new ClosedChannelException();
                    k = ((AbstractSelector)sel).register(this, ops, att);
                    addKey(k);
                }
            }
            return k;
        }
    }
{code}
And this is how {{findKey}} works:
{code:java}
    private SelectionKey findKey(Selector sel) {
        synchronized (keyLock) {
            if (keys == null)
                return null;
            for (int i = 0; i < keys.length; i++)
                if ((keys[i] != null) && (keys[i].selector() == sel))
                    return keys[i];
            return null;
        }
    }
{code}
As you can see, when using a new instance of the selector, {{findKey}} will 
return {{null}} because {{keys[i].selector() == sel}} *cannot* be {{true}}.

Leter when {{((AbstractSelector)sel).register(this, ops, att)}} is called a new 
instance of {{SelectionKeyImpl}} is created:
{code:java}
    protected final SelectionKey register(AbstractSelectableChannel var1, int 
var2, Object var3) {
        if (!(var1 instanceof SelChImpl)) {
            throw new IllegalSelectorException();
        } else {
            SelectionKeyImpl var4 = new SelectionKeyImpl((SelChImpl)var1, this);
            var4.attach(var3);
            Set var5 = this.publicKeys;
            synchronized(this.publicKeys) {
                this.implRegister(var4);
            }

            var4.interestOps(var2);
            return var4;
        }
    }
{code}
{quote}Once the old selector is closed, it does not retain references to 
selection keys.
{quote}
This is not actually what happens. As it was also pointed out in DIRMINA-1042, 
{{EPollSelectorImpl}} will not clear the {{fdToKey}} map so all the keys there 
will still be referenced.

 

Looking forward to hearing your thoughts

Juan Palacios.

> Massive object graph in NioSocketSession
> ----------------------------------------
>
>                 Key: SSHD-854
>                 URL: https://issues.apache.org/jira/browse/SSHD-854
>             Project: MINA SSHD
>          Issue Type: Bug
>            Reporter: jpalacios
>            Priority: Major
>
> I'm looking at a heap dump from one of our customers where the retained heap 
> size for some {{NioSocketSession}} instances is almost 1GB.
> From the looks of the dump MINA has created a massive object graph where:
> {code}
> NioSocketSession -> SelectionKeyImpl -> EpollSelectorImpl -> HashMap -> 
> SelectionKeyImpl -> NioSocketSession -> ...
> {code}
> From the looks of the obeject IDs these are not loops
> Each individual object is not large by itself but at the top of the graph the 
> accumulated retained size is enough to produce an OOME
> Could you help me understand how MINA can produce such a massive object 
> graph? Should MINA apply any defense mechanism to prevent this??



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

Reply via email to