资讯专栏INFORMATION COLUMN

Netty之ByteBuf深入分析

caikeal / 752人阅读

摘要:对于小内存小于的分配还会将细化成更小的单位。按大小分有两大类,种情况小于的情况,最小空间为,对齐大小为,区间为,所以共有种情况。大于等于的情况,总共有四种,。

Netty之ByteBuf深入分析

[TOC]

分析思路 内存与内存管理器的抽象 ByteBuf 结构以及重要的API
ByteBuf 数据结构
* {@link ByteBuf} provides two pointer variables to support sequential
 * read and write operations - {@link #readerIndex() readerIndex} for a read
 * operation and {@link #writerIndex() writerIndex} for a write operation
 * respectively.  The following diagram shows how a buffer is segmented into
 * three areas by the two pointers:
 *
 * 
 *      +-------------------+------------------+------------------+
 *      | discardable bytes |  readable bytes  |  writable bytes  |
 *      |                   |     (CONTENT)    |                  |
 *      +-------------------+------------------+------------------+
 *      |                   |                  |                  |
 *      0      <=      readerIndex   <=   writerIndex    <=    capacity
 * 
* *

Readable bytes (the actual content)

read ,write set 方法
mark 和 reset方法
ByteBuf 分类
Pooled 和 Unpooled

Pooled池化内存分配每次从预先分配好的一块内存取一段连续内存封装成ByteBuf提供给应用程序,

Unpooled非池化每次进行内存分配的时候调用系统API向操作系统申请一块内存

Unsafe 和 非Unsafe

Unsafe直接获取ByteBuf在JVM内存地址调用JDK的Unsafe进行读写操作,通过ByteBuf分配内存首地址和当前指针基于内存偏移地址获取值,

非Unsafe不依赖JDK的Unsafe对象,通过内存数组和索引获取值

Heap和Direct

Heap在堆上进行内存分配,分配内存需要被GC管理,无需手动释放内存,依赖底层byte数组,

Direct调用JDK的API进行内存分配,分配内存不受JVM控制最终不会参与GC过程,需要手动释放内存避免造成内存无法释放,依赖DirectByteBuffer对象内存

内存分配器ByteBufAllocator分析
ByteBufAllocator功能

buffer()方法分配内存是否为Direct/Heap内存依赖具体实现,

ioBuffer()方法分配内存更希望是适合IO的Direct Buffer,directBuffer()/headBuffer()方法堆内/堆外进行内存分配,compositeBuffer()方法分配将两个ByteBuf合并变成CompositeByteBuf

AbstractByteBufAllocator

buffer()方法分配Buffer依赖实现分配内存,调用directBuffer()/heapBuffer()方法分配默认Buffer容量和最大扩充容量的ByteBuf,newDirectBuffer()/newHeapBuffer()方法分配Pooled/Unpooled依赖底层实现

ByteBufAllocator两个子类

PooledByteBufAllocator从预先分配好的内存取一段内存,

UnpooledByteBufAllocator调用系统API分配内存,调用hasUnsafe()方法获取Unsafe决定分配Unsafe/非Unsafe

UnpooledByteBufAllocator分析
heap内存的分配

newHeapBuffer()方法通过hasUnsafe()方法判断是否有Unsafe

传递initialCapacity容量Byte数组参数setArray()方法设置array以及setIndex()方法设置读/写指针

创建UnpooledUnsafeHeapByteBuf/UnpooledHeapByteBuf,

_get***()方法通过Unsafe方式返回数组对象偏移量[BYTE_ARRAY_BASE_OFFSET+index]对应的byte/数组索引方式返回array数组index位置byte

direct内存的分配

newDirectBuffer()方法通过hasUnsafe()方法判断是否有Unsafe

调用allocateDirect(initialCapacity)创建DirectByteBuffer

使用setByteBuffer()方法设置buffer[UnpooledUnsafeDirectByteBuf

使用directBufferAddress()方法获取buffer内存地址设置memoryAddress

创建UnpooledUnsafeDirectByteBuf/UnpooledDirectByteBuf,

_get***()方法通过addr()方法memoryAdress+index计算内存地址

Unsafe获取对应这块内存的byte/ByteBuffer获取buffer index位置对应的byte

不同规格大小和不同类别的内存的分配策略 内存规格介绍
 0 <-tiny->512B<-small->8K<-normal->16M<-huge->
 |______________________|            |
          SubPage      Page        Chunk

16M作为分界点对应的Chunk,

所有的内存申请以Chunk为单位向操作系统申请,

内存分配在Chunk里面执行相应操作,

16M Chunk按照Page进行切分为2048个Page,8K Page按照SubPage切分

内存的回收过程 常见问题 Netty 的内存的类别有哪些? 堆内内存/堆外内存

堆内[基于2048byte字节内存数组分配]

堆外[基于JDK的DirectByteBuffer内存分配]

Unsafe/非Unsafe

Unsafe[通过JDK的Unsafe对象基于物理内存地址进行数据读写]

非Unsafe[调用JDK的API进行读写]

UnPooled/Pooled

UnPooled[每次分配内存申请内存]

Pooled[预先分配好一整块内存,分配的时候用一定算法从一整块内存取出一块连续内存]

如何减少多线程内存分配之间的竞争关系?

PooledByteBufAllocator内存分配器结构维护Arena数组,所有的内存分配都在Arena上进行,

通过PoolThreadCache对象将线程和Arena进行一一绑定, 默认情况一个Nio线程管理一个Arena实现多线程内存分配相互不受影响减少多线程内存分配之间的竞争

不同大小的内存是如何进行分配的?

Page级别的内存分配通过完全二叉树的标记查找某一段连续内存,

Page级别以下的内存分配首先查找到Page然后把此Page按照SubPage大小进行划分最后通过位图的方式进行内存分配

不同大小的内存是如何进行分配的?2

Netty一次向系统申请16M的连续内存空间,这块内存通过PoolChunk对象包装,进一步的把这16M内存分成了2048个页(pageSize=8k)。页作为Netty内存管理的最基本的单位 ,所有的内存分配首先必须申请一块空闲页。
对于小内存(小于4096)的分配还会将Page细化成更小的单位Subpage。Subpage按大小分有两大类,36种情况:Tiny:小于512的情况,最小空间为16,对齐大小为16,区间为[16,512),所以共有32种情况。Small:大于等于512的情况,总共有四种,512,1024,2048,4096。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/77039.html

相关文章

  • Netty 源码分析 三 我就是大名鼎鼎的 EventLoop(二)

    摘要:接上篇源码分析之三我就是大名鼎鼎的一的处理循环在中一个需要负责两个工作第一个是作为线程负责相应的操作第二个是作为任务线程执行中的任务接下来我们先从操纵方面入手看一下数据是如何从传递到我们的中的是模型的一个实现并且是基于的那么从的前生今世之四 接上篇Netty 源码分析之 三 我就是大名鼎鼎的 EventLoop(一) Netty 的 IO 处理循环 在 Netty 中, 一个 Even...

    whidy 评论0 收藏0
  • Netty Zero-copy 的实现(上)

    摘要:维基百科中对的解释是零拷贝技术是指计算机执行操作时,不需要先将数据从某处内存复制到另一个特定区域。维基百科里提到的零拷贝是在硬件和操作系统层面的,而本文主要介绍的是在应用层面的优化。 维基百科中对 Zero-copy 的解释是 零拷贝技术是指计算机执行操作时,CPU不需要先将数据从某处内存复制到另一个特定区域。这种技术通常用于通过网络传输文件时节省CPU周期和内存带宽。 维基百科里提到...

    sf_wangchong 评论0 收藏0
  • 彻底理解Netty,这一篇文章就够了

    摘要:如果什么事都没得做,它也不会死循环,它会将线程休眠起来,直到下一个事件来了再继续干活,这样的一个线程称之为线程。而请求处理逻辑既可以使用单独的线程池进行处理,也可以跟放在读写线程一块处理。 Netty到底是什么 从HTTP说起 有了Netty,你可以实现自己的HTTP服务器,FTP服务器,UDP服务器,RPC服务器,WebSocket服务器,Redis的Proxy服务器,MySQL的P...

    yy13818512006 评论0 收藏0
  • Netty ByteBuf

    摘要:主要用来检测对象是否泄漏。子类实现相关的方法是否支持数组,判断缓冲区的实现是否基于字节数组如果缓冲区的实现基于字节数组,返回字节数组 ByteBuf ByteBuf需要提供JDK ByteBuffer的功能(包含且不限于),主要有以下几类基本功能: 7种Java基础类型、byte[]、ByteBuffer(ByteBuf)的等的读写 缓冲区自身的copy和slice 设置网络字节序 ...

    meislzhua 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<