Netty学习笔记 ByteBuf

147 阅读3分钟

ByteBuf就是一个Byte数组缓存区  

  通过readerIdnex和writerIndex来协助读写操作 还有个capacity指针表明容量 

  会自动进行动态扩容

 Discardable Bytes

相比其他Java对象,缓冲区的分配和释放是一个耗时的操作,所以需要尽量重用.可以使用discardReadBytes将数组往已读部分移动,从而复用已读部分,增大可写空间.但这存在内存复制的现象,所以频繁使用会导致性能下降.

clear  :将缓冲区填充为Null(0x00) 同时还原reader/writerIndex

mark对应指针 记录该指针当前位置 之后再reset可以将指针移动到该位置  比如预留空间给之后数组长度,之后回滚到这记录

各种查找操作

复制ByteBuf duplicate(共享空间不共享指针) copy(空间指针都不共享  就是复制)

通过Nio的SocketChannel进行网络读写时,操作的对象时JD看到ByteBuffer 所以要将ByteBuf转化为ByteBuffer,   nioBuffer()    //int index  int length  支持随机读写

ByteBuf 根据内存位置可以分为两大类:堆内存和直接内存

直接内存:在堆外进行内存回收 所以少从直接缓存和堆内缓存之间的复制,少了Java堆对应的复制,也就是所谓的零拷贝的一种,但不受到JVM GC 管理

经验表面: I/O通信读写缓存使用直接内存  后台业务消息的编解码使用堆内存性能最优

 根据内存回收也可以分为两类 : 基于对象池和普通ByteBuf

  基于对象池可以使用内存池重用ByteBuf对象

PooledByteBuf内存池(堆内)

实现类 PoolArena(Arena指一大块区域)

由多个Chunk组成,每个Chunk由一个或者多个Page构成    Chunk中Page会给构建成一个二叉树,根为所有Page的内存,当树的一个节点被分配出去后,节点会被标记为已分配,之后对这个节点及其子节点的请求就会被忽略.请求分配就只能找其他节点.  

对于小于Page大小的请求  会将一个Page进行拆分(按请求大小等分),之后只能再将其他部分分配给等大小的请求.  Page使用状态通过long数组维护 0表示未占用 1占用  

PooledDirectByteBuf 实现类似 ,唯一不同就是分配和创建策略不同

第二种零拷贝:  可以将多个ByteBuf统一封装后向外提供一个ByteBuf不需要复制.

第三种零拷贝:直接将文件缓冲区的内容直接发送到Channel(网卡 大概是).

ByteBuf的释放

1.基于内存池的请求ByteBuf

由NioEventLoop分配,需要在ChannelInboundHandler后释放     此处释放指释放给内存池

()继承自SimpleChannelInboundHandler可以自动释放

  ()调用ctx.fireChannelRead(msg);将请求消息向后执行 直到Tail释放请求

非内存池请求ByteBuf也会释放

响应ByteBuf   

ctx.writeAndFulsh.中Netty会在消息发送完成后协助释放内存,Heap内存会转化成Direct 并释放Heap内存  Direct会在消息完整写到SocketChannel后释放

所以调用了writeAndFulsh或者fulsh就不用业务释放