Netty源码解析(4)-内存分配

ByteBuf直接与底层IO打交道

1、内存类别有哪些

2、如何减少多线程内存分配竞争

3、不同大小内存是如何分配的

内存与内存管理器的抽象

不同规格大小和不同内存类别的分配策略

内存回收

ByteBuf结构

  readerIndex,表示要读数据从当前指针开始读,从0到readerIndex这段空间表示是无效的

  writerIndex,必须大于readerIndex,表示要写数据从当前指针开始写,从readerIndex到writerIndex这段空间表示可以读的

  capacity,必须,从writerIndex到capacity这段空间表示空闲可以写的

ByteBuf API

  read,从readerIndex往后开始读

  write 从writerIndex往后开始写

  set 不移动任何指针,直接再当前指针地方进行设置

  markReaderIndex 将readerIndex进行保存起来

  resetReaderIndex 将readerIndex进行恢复,这样读数据就不会移动指针

  markWriterIndex 同上

  resetWriterIndex  同上

  readableBytes() writerIndex - readerIndex

  writeableBytes() capacity - writerIndex

ByteBuf分类

  

 

   Pooled和UnPooled,内存分配时从已经分配的一块内存中分配一块,有预分配过程,UnPooled就是直接向操作系统申请内存

  Unsafe和非UnSafe,Unsafe可以直接拿到内存地址,可以直接拿到ByteBuf在JVM内存通过内存地址和偏移量,非unsafe可以直接调用jdk api读写,通过数组和下标访问数据,。jdk自动判断Unsafe或者非Unsafe

  Heap和Direct,在堆上直接分配,jc自动回收管理,依赖一个数组,Direct调用jdk api分配不会被jvm内存回收管理,依赖jdk底层的ByteBuffer。

ByteBufAllocator 内存管理器

    AbstractByteBufAllocator骨架实现

      UnPooledByteBufAllocator,直接分配一个容量大小的数组

        newHeapBuffer 在堆上new一个数组出来传入并保存

        newDirectBuffer 依赖于jdk底层ByteBuffer,保存初始地址和容量。

      PooledByteBufAllocator,首先拿到线程局部缓存,PoolThreadCache先创建PoolArena<byte[]>,PoolArena<ByteBuf>这两种内存池,在线程上的Arena上进行内存分配。创建内存分配器时会创建两种类型的数组,PoolArena.HeapArena和PoolArena.directArena

        newHeapBuffer

        newDirectBuffer,分配的内存要自己负责回收

  DirectArena分配direct内存的流程

    从对象池里面拿到的PooledByteBuf进行复用

    从缓存上进行分配

    从内存堆里面进行内存分配

内存规格介绍

tiny 0-512

small  512B-8k subpage

normal  8K-16M page

huge 16M以上 chunk

缓存数据结构

MemoryRegionCache

queue <chunk,handler>

sizeClass tiny[32] small[4]         normal[3]

size N*16B  512B、1K、2K、4k  8k 16k 32k

 内存分配先根据size从数组里面取出MemoryRegionCache,然后冲queue里面弹出一个entry给ByteBuf初始化,将弹出的entry扔到对象池进行复用,entry里面有chunk表示再那块内存上分配,handler表示起始地址。

arena,chunk,page,subpage,每个线程去分配对应内存,首先通过threadlocal,拿到pooledThreadCache。Arena直接开辟一块内存,参考pooledArena里面6个chunklist

 

 page级别的内存分配:allocateNormal()

尝试在现有的chunk上进行分配

创建一个chunk进行内存分配

初始化PooledByteBuf

 

 subpage内存分配

定位一个subpage对象

初始化subpage

初始化PooledByteBuf

ByteBuf对象回收

连续的内存区段加入到缓存

标记连续的内存区段为未使用

ByteBuf加入对象池

 

posted on 2020-04-12 22:03  清浊  阅读(345)  评论(0编辑  收藏  举报