首页 > 技术文章 > Mina 组件介绍之 IoBuffer

luojiahu 2018-02-25 12:50 原文

  在Java NIO 中,ByteBuffer通常作为通信中传递消息的载体。而在Mina中,采用了IoBuffer代替ByteBuffer。Mina给出了不用ByteBuffer的两个主要理由:

1.  ByteBuffer未提供一些常用到的get/set方法,如:fill, get/putString, get/putAsciiInt

这里附上,fill方法在AbstractIoBuffer中的实现,可以看到程序分别采用Long,Int,Short,byte对指定size的byte内容进行了快速填充,而不是采用for循环,是个有趣的技巧。

public IoBuffer fill(byte value, int size) {
        autoExpand(size);
        int q = size >>> 3;
            int r = size & 7;

            if (q > 0) {
                int intValue = value | value << 8 | value << 16 | value << 24;
                long longValue = intValue;
                longValue <<= 32;
                longValue |= intValue;

                for (int i = q; i > 0; i--) {
                    putLong(longValue);
                }
            }

            q = r >>> 2;
                r = r & 3;

                if (q > 0) {
                    int intValue = value | value << 8 | value << 16 | value << 24;
                    putInt(intValue);
                }

                q = r >> 1;
                    r = r & 1;

                    if (q > 0) {
                        short shortValue = (short) (value | value << 8);
                        putShort(shortValue);
                    }

                    if (r > 0) {
                        put(value);
                    }

                    return this;
    }

2. ByteBuffer一旦分配,容量固定,不易扩展。

  在Mina的实现中,IoBuffer的扩展是通过重新分配一块新的更大的ByteBuffer,并把旧的ByteBuffer拷贝到新的当中实现的,这种实现的问题显而易见,可能导致频繁分配内存,生成内存碎片。另外,在用户使用DirectBuffer时,频繁的内存分配和释放(ByteBuffer.clear())可能导致内存不能及时回收,从而导致内存泄漏。关于IoBuffer自动扩展的问题在Mina的官方网站上也有提及:

This will change in MINA 3. The main reason why MINA has its own wrapper on top of nio ByteBuffer is to have extensible buffers. This was a very bad decision. Buffers are just buffers : a temporary place to store temporary data, before it is used. Many other solutions exist, like defining a wrapper which relies on a list of NIO ByteBuffers, instead of copying the existing buffer to a bigger one just because we want to extend the buffer capacity.
It might also be more comfortable to use an InputStream instead of a byte buffer all along the filters, as it does not imply anything about the nature of the stored data : it can be a byte array, strings, messages...

Last, not least, the current implementation defeat one of the target : zero-copy strategy (ie, once we have read the data from the socket, we want to avoid a copy being done later). As we use extensible byte buffers, we will most certainly copy those data if we have to manage big messages. Assuming that the MINA ByteBuffer is just a wrapper on top of NIO ByteBuffer, this can be a real problem when using direct buffers.

总结起来主要是:0. 实现自动扩展是错误的决定; 1. 可以有更好的实现方式,如ByteBuffer List;  2. 违反了zero-copy 原则;  3. 在用户使用Direct模式管理较大的Message存在内存泄漏的风险。

可见Mina对于ByteBuffer的包装IoBuffer是存在一定问题的,官方考虑放弃。但是Mina社区目前基本处于停滞状态。(最新的稳定版本时间还是2016年10月)

推荐阅读