**Netty简述**

    netty 是 java的一个io框架, 它简化了nio编程,提高了io的性能和可靠性,是服务端常用的框架之一,在大数据系统中也是很常见的一个框架。
    官方说明中,netty 主要提供了创建私有协议的解决方案。
    **缓冲区**

    io 编程中少不了对缓冲区的操作,缓冲区,就是一片连续的内存地址空间,也就是数组。数据通过流传输的效率低下,通过缓冲区就可以实现块传输。
    **ByteBuf**

    java nio库中已经存在了一个Buffer类,但是操作起来容易出错,每次读取都需要做flip操作,且功能有限,动态扩张等有用的特性,需要自己编程实现。
    netty提供了一个新的缓冲类实现:ByteBuf解决了上述问题。
    ByteBuf 有两个指针,一个读指针,一个写指针,它的设计如下:

java输出Netty缓冲区大小 netty设置缓冲区大小_编程

当需要往缓冲区写数据时,writerIndex向前移动,当需要读数据时,readerIndex向前移动,读的位置始终不能超过写的位置。
     当写入了y份数据,读取了x份数据后,缓冲区将出现一部分discard 区域 。这种情况出现在粘包的情况,一次数据流传送中包含了多个数据包,前面的流包含的若干数据包已经被解析,后面的流继续写入。其状态图如下:

java输出Netty缓冲区大小 netty设置缓冲区大小_框架_02

**缓冲区空间不足时**

    这时候如果数据继续写入缓冲区,而缓存区的writable区间已经被判断空间不足,那就有两个方法可以解决:

    **1、动态扩展缓冲区,由ByteBuf 实现,用户无感知。**

    动态扩展缓冲区的原理,是新建一个更大的缓冲区,把在原来缓冲区的内容复制到新的缓冲区,然后就有更大的空间可以写入了。中间涉及内存的分配和内存复制,所以扩容的成本较高。
    netty缓存扩容的策略一方面要让扩容能满足后面写入的需求,不能扩容之后,马上缓冲区又被填满,又需要再一次的扩容。另一方面不能一次性扩容太多,导致内存浪费。所以一般是先倍增,再步增,举个例子,原来缓存区1M,扩容到2M,再扩容到4M,再扩容到8M,如果再继续倍增,那扩容的内存就太多了,之后就采取每次扩容4M的方式,扩容到12M,再扩容到16M。

    **2、重用discard 区域,需要调用discardReadBytes方法。**

    重用discard 区域的原理是将readable区域复制到前面,以0为起始坐标,然后重置readerIndex和writerIndex,当然还有这里没提到的标记指针。这里需要一次内存复制,还是会消耗额外的性能。重用后的缓冲区如下所示:

    **netty缓冲区使用**

    netty的缓存区设计不仅可以用到io上,再我们java编程的过程中需要用到缓冲区的地方都可以使用。
    一般io编程使用直接内存的缓冲区,而其他操作可以使用堆缓冲区。
    netty 包中还有缓冲区池的实现,让缓冲区可以得到重用,类图如下(图出自netty权威指南):

java输出Netty缓冲区大小 netty设置缓冲区大小_java输出Netty缓冲区大小_03