暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Kmalloc 共享内存池技术架构详解

原创 KaiwuDB 2023-03-30
1040

Kmalloc 共享内存池简介

在不同应用场景中,内存占用大小和申请释放频率各有不同。因此,需要根据实际情况对内存进行分类管理,从而提升内存管理的效率。但内存池在使用一段时间后往往会出现内存碎片,导致即使空闲内存很多,却无法申请大块内存,造成内存利用率降低。

在某些业务场景中,还需要跨进程进行数据共享。同时在内存池的使用过程中,我们需要了解内存池的使用情况,检测内存泄漏、重复释放、内存越界等异常情况。Kmalloc 是开务数据库自研的一款共享内存池,其重点采用了以下攻克方式:

  • 为了满足不同类型内存的使用,我们将内存池分为多个 Heap,每个 Heap 使用不同的结构管理不同类型的内存。

  • 为了提高内存利用率,我们在申请和释放内存时做了一些额外的优化处理。

  • 为了实现高速的数据共享,我们允许多个进程访问同一块内存,并使用并发访问控制来管理内存的释放。

  • 为了监控内存池使用情况,我们提供了一些内存池 Stats 接口和 Debug 模式。

Kmalloc 共享内存池的架构

1、内存池区域划分

Kmalloc 共享内存池由 Header Heap、Free Heap、Common Heap、TS Data Heap、System Heap 组成,初始化时先按照预设参数大小向操作系统申请并固定共享内存,而后完成各个 Heap 的初始化。

在共享内存头部区域固定下的内存作为 Header Heap,用来存放产品其他模块和 Kmalloc 的 Header;剩余的内存全部用来初始化 Free Heap;其他 3 个 Heap 向 Free Heap 申请内存。

2、内存分类管理

内存按照使用场景,可分成不同的 MemType,由不同的 Heap 进行管理:

内存按照大小分别由不同的数据结构进行管理:

  • Thread Cache 和 CentralCache由若干条 Freelist 构成,每条 Freelist 由相同大小的内存块采用嵌入式指针连接而成。

  • PageHeap 也由若干 Freelist 构成,区别在于 Freelist 中的元素为 Span 结构体。

  • SkipList 则是一条 Span 按照内存大小排序的跳表。

大块连续的内存按照 Page(8K) 为最小单位进行追踪,一个或多个连续的 Page 构成一个 Span,由 Span 结构体记录它的 Page 范围、MemType 等详细信息。Page ID 与 Span 的映射关系由 Page Map(通过 Radix-Tree 实现,如下图)进行维护。

3、内存池区域****结构

除 Header Heap 外,每个 Heap 根据其管理内存的特点,分别由不同的数据结构组成。Common Heap 的结构及内存申请释放流程如下。

其他 3 个 Heap 都是 Common Heap 的简化:TSData Heap 由 Thread Cache 和 Central Cache 构成,System Heap 只包含 Central Cache,Free Heap 只包含 SkipList。

Kmalloc 共享内存池如何提高内存利用率

1、使用嵌入式指针连接 Freelist 中的元素。
2、内存对齐:
  • 小内存映射到一个对齐的大小类型作为实际申请的内存大小,最低 8 字节对齐,且随着内存大小的增长,对齐的单位也相应地增大。

  • 中大内存以 Page 为单位向上取整。

3、避免申请小块内存:
  • Central Cache 向 Page Heap 申请内存时,最小单位是 Page。

  • 各个 Heap 向 Free Heap 申请内存时,如果实际需要的内存不满 1 M,先尝试申请 1M 内存;如果申请失败,再尝试申请实际需要的内存大小。

4、内存 GC 算法:

Thread Cache 和 Central Cache 采用 GC 算法使闲置的内存快速释放回上一层。Page Heap 和 SkipList 收到下层释放的内存后,会尽量将相邻的空闲内存合。

Kmalloc 共享内存的并发访问管理

**使用场景:**进程 A 从共享内存池申请了一块内存,共享给进程B。具体流程如下:

  • 进程 A 调用注册共享内存的接口,将进程 ID 记录到引用计数器中,并得到相应的内存偏移量。

  • 使用消息队列将偏移量传送给进程 B。

  • 进程 B 收到偏移量后,调用访问共享内存的接口,将其转换成具体的内存地址,并将进程 ID 记录到引用计数器中。然后通过类型转换,即可访问该内存。

  • 两个进程在使用完共享内存后,都需要调用 Free 释放对内存的引用,当引用为 0 时真正释放内存。

  • 如果进程 B 未释放内存引用就 Crash,进程 A 可以调用内存引用释放接口,主动释放进程 B 的内存引用。

Kmalloc 监控与异常检测

1、内存使用情况监控
  • 提供查询内存池使用情况的接口,查询内存池当前使用内存的总大小和历史峰值、Free Heap剩余的内存大小等信息。

  • Free Heap 内存预警,当 Free Heap 剩余内存大小不足 80% 时,将输出预警信息。

2、Debug 模式

通过在分配的内存首尾添加 Debug Header、Debug Mark 和 Debug Tail,分别检测内存泄漏、重复释放、越界访问等问题。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论