加入收藏 | 设为首页 | 会员中心 | 我要投稿 辽源站长网 (https://www.0437zz.com/)- 云专线、云连接、智能数据、边缘计算、数据安全!
当前位置: 首页 > 服务器 > 系统 > 正文

Netty中的数据容器分类使用方式及其空间分配

发布时间:2021-05-30 10:11:09 所属栏目:系统 来源:互联网
导读:谈到数据保存肯定要说到内存分配,按照存储空间来划分,可以分为堆内存和堆外内存;按照内存区域连贯性来划分可以分为池化内存和非池化内存。这些划分在 Netty 中

谈到数据保存肯定要说到内存分配,按照存储空间来划分,可以分为堆内存和堆外内存;按照内存区域连贯性来划分可以分为池化内存和非池化内存。这些划分在 Netty 中的实现接口分别如下。

按照底层存储空间划分:

堆缓冲区:HeapBuffer

直接缓冲区:DirectBuffer

按照是否池化划分:

池化:PooledBuffer

非池化:UnPooledBuffer

默认使用 PoolDireBuf 类型的内存,这些内存主要由 PoolArea 管理。另外 Netty 并不是直接对外暴露这些 API,提供了 Unsafe 类作为出口暴露数据分配的相关操作。

什么是池化?

一般申请内存是检查当前内存哪里有适合当前数据块大小的空闲内存块,如果有就将数据保存在当前内存块中。

那么池化想做的事情是:既然每次来数据都要去找内存地址来存,我就先申请一块内存地址,这一块就是我的专用空间,内存分配、回收我全权管理。

池化解决的问题:内存碎片。

内碎片:就是申请的地址空间大于真正数据使用的内存空间。

比如固定申请 1M 的空间作为某个线程的使用内存,但是该线程每次最多只占用 0.5M,那么每次都有 0.5M 的碎片。如果该空间不被有效回收时间一长必然存在内存空洞。

外碎片:是指多个内存空间合并的时候发现不够分配给待使用的空间大小。

比如有一个 20byte,13byte 的连续内存空间可以被回收,现在有一个 48byte 的数据块需要存储,而这两个加起来也只有 33byte 的空间,必然不会被使用到。

如何实现内存池?

①链表维护空闲内存地址

最简单的就是弄一个链表来维护当前空闲的内存空间地址。如果有使用就从链表删除,有释放就加入链表对应位置。

这种方式实现简单,但是搜索和释放内存维护的难度还是比较大,不太适合。

②定长内存空间分配

维护两个列表,一个是未分配内存列表,一个是已分配内存列表。每个内存块都是一样大小,分配时如果不够就将多个块合并到一起。

这种方式的缺点就是会浪费一定的内存空间,如果有特定的场景还是没有问题。

③多段定长池分配

在上面的定长分配基础上,由原来的固定一个长度分配空间变为按照不同对象大小(8,16,32,64,128,256,512,1k…64K),的方式分配多个固定大小的内存池。

每次要申请内存的时候按照当前对象大小去对应的池中查找是否有剩余空间。

Linux 本身支持动态内存分配和释放,对应的命令为:malloc/free。malloc 的全称是 memory allocation,中文叫动态内存分配,用于申请一块连续的指定大小的内存块区域以 void* 类型返回分配的内存区域地址。

malloc/free 的实现过程:

空闲存储空间以空闲链表的方式组织(地址递增),每个块包含一个长度、一个指向下一块的指针以及一个指向自身存储空间的指针。(因为程序中的某些地方可能不通过 malloc 调用申请,因此 malloc 管理的空间不一定连续)

当有申请请求时,malloc 会扫描空闲链表,直到找到一个足够大的块为止。(首次适应)(因此每次调用 malloc 时并不是花费了完全相同的时间)

如果该块恰好与请求的大小相符,则将其从链表中移走并返回给用户。如果该块太大,则将其分为两部分,尾部的部分分给用户,剩下的部分留在空闲链表中(更改头部信息)。因此 malloc 分配的是一块连续的内存。

释放时首先搜索空闲链表,找到可以插入被释放块的合适位置。如果与被释放块相邻的任一边是一个空闲块,则将这两个块合为一个更大的块,以减少内存碎片。

(编辑:辽源站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读