DPDK18.11.11 内存管理和分配的解析


风晓
风晓 2024-01-05 10:45:44 49750 赞同 0 反对 0
分类: 资源
一、DPDK的内存模式 DPDK存在两种内存模式:


1、legacy mode : 这一种为静态内存模式,即在初始化过程就根据配置分配所有的内存,并且这些内存页在application结束之前不会归还给OS;而且也不会再向OS申请更多的内存。并且application使用DPDK的rte_malloc库申请内存时,若剩余可用的内存不足,则直接返回错误。这种模式的优点是若一段内存空间的虚拟内存地址是连续的,那么其物理内存地址也是连续的。

2、dynamic mode:这一种为动态内存模式,在初始化过程根据配置分配所需要的内存,并且这些内存页在application结束之前不会归还给OS。若application使用DPDK的rte_malloc库申请内存时,若剩余可用的内存不足,则会先向操作系统申请内存,再将这些内存分配给application。由于会动态地向OS申请内存,所以虚拟内存连续并不意味着物理内存连续。(对于向操作系统动态申请的内存,在application释放这些内存时,DPDK系统会将其归还给OS,不必等到application结束)

二、相关结构体的说明

下面先对一些结构体的字段进行说明(参考后面的图例能更容易的理解),能够帮助对后面的理解:

 
**********************************malloc_elem.h*****************************
struct malloc_elem {
struct malloc_heap *heap;
struct malloc_elem *volatile prev; //指向上一个malloc_elem
/**< points to prev elem in memseg */
struct malloc_elem *volatile next;  // 指向下一个malloc_elem
/**< points to next elem in memseg */
LIST_ENTRY(malloc_elem) free_list; //指向下一个free malloc_elem
/**< list of free elements in heap */
struct rte_memseg_list *msl;
volatile enum elem_state state; //表明malloc_elem的状态: free, 或者busy
uint32_t pad; //填充无效的内存区域
size_t size; // 表示malloc_elem所表示的内存区域的大小(包含struct malloc_elem), 以字节为单位
struct malloc_elem *orig_elem;  //指向最初的malloc_elem(即内存初始化时的malloc_elem)
size_t orig_size; //最初的malloc_elem的内存区域的大小
#ifdef RTE_MALLOC_DEBUG
uint64_t header_cookie;         /* Cookie marking start of data */
                                /* trailer cookie at start + size */
#endif
} __rte_cache_aligned;
**********************************rte_malloc_heap.h*****************************
struct malloc_heap {
rte_spinlock_t lock;
LIST_HEAD(, malloc_elem) free_head[RTE_HEAP_NUM_FREELISTS];
/*
free_head用于存放free malloc_elem的位置
free_head[0] 存放由大小为(0, 2^8]的free malloc_elem组成的链表头指针
free_head[1] 存放由大小为(2^8, 2^10]的free malloc_elem组成的链表头指针
free_head[2] 存放由大小为(2^10, 2^12]的free malloc_elem组成的链表头指针
free_head[3] 存放由大小为(2^12, 2^14]的free malloc_elem组成的链表头指针
······
以此类推
*/
struct malloc_elem *volatile first; //指向heap的第一个malloc_elem
struct malloc_elem *volatile last; // 指向heap的最后一个malloc_elem
 
unsigned alloc_count; //已经分配的malloc_elem的数量
unsigned int socket_id;
size_t total_size; //表示此heap所包含的内存(以字节为单位)
char name[RTE_HEAP_NAME_MAX_LEN];
} __rte_cache_aligned;
 

三、DPDK内存管理结构

在这里,我们抛弃struct rte_memseg_list, struct rte_memseg的观点。单纯地从struct malloc_heap和struct malloc_elem的角度来看DPDK的内存管理,如下图所示 :
在这里插入图片描述
这是一个刚初始化完成的heap,只包含free malloc_elem。
可以看出DPDK的内存管理主要由一个双向链表组成:malloc_heap包含first, last指针,分别指向第一个malloc_elem和最后一个malloc_elem;每一个malloc_elem有一个prev和next指针(如图中黑色的线条所示)。图中蓝色的线表示的是由malloc_heap中的 free_head 和malloc_elem中的 free_list 构成的free malloc_elem的链表。

DPDK中的rte_malloc库中,application使用 rte_malloc() 方法向DPDK的运行时系统申请内存,rte_free() 释放内存。其它向heap申请或释放内存的方法基本也是调用这两个方法 :
1,rte_malloc() : 这个方法主要是调用了 malloc_heap_alloc()(位于malloc_heap.c) 进行分配内存。并且每次分配时,都会从一个free malloc_elem的末尾开始分配。
2,rte_free() : 这个方法主要是调用了 malloc_heap_free()(位于malloc_heap.c) 将内存释放回DPDK系统。

下面用一个场景说明内存的分配和释放过程:
一, rte_malloc()分配一块内存后,malloc_heap变化如下 :

在这里插入图片描述
分配完后的结果如上图所示,每一次分配的基本步骤如下:
1, 根据需要分配的内存的大小从对应的free_head中查找到合适的free malloc_elem,如果没有,则向OS申请额外的内存(通过eal_memalloc_alloc_seg_bulk() 申请),作为新的free malloc_elem加入到heap中,对其进行扩展。
2, 从free malloc_elem的末尾开始分配内存,然后将free malloc_elem划分为两个malloc_elem, 后面一个标记为busy malloc_elem。
3, 修改malloc_elem的prev, next指针,并且将剩余的free malloc_elem加入到合适的free链表的头部。

二,执行rte_free()释放刚才分配的内存,malloc_heap的变化如下:
在这里插入图片描述
释放完后的结果如上图所示,每一次释放的基本步骤如下:
1, 将要进行释放的busy malloc_elem的状态标记为free
2, 检查有没有在内存上并且也是free的malloc_elem, 存在的话就合并为一个大的free malloc, 然后加入到合适的free链表的头部。
3, 检查能否归还向OS申请的额外内存,如果可以的话,就将其归还给OS(通过 eal_memalloc_free_seg_bulk() 归还)。

四,底层实现
DPDK在memalloc时有两种模式single-file-segments, page-per-file。 每一种都在hugetlbfs的挂载点上有相应的文件形式(即存在于内存中的文件),这样在内存分配时可以使用对file descriptor操作的系统调用对内存进行操作。
下面对这两种模式进行进一步的解释 :
single-file-segment的映射关系如下:
在这里插入图片描述
蓝色表示的是内存文件所占用的物理内存,对于一个rte_memseg_list会创建一个文件,rte_memseg_list中的mem_segment会和文件的其中一部分进行映射。

page-per-file的映射关系如下:
在这里插入图片描述
蓝色表示的是内存文件所占用的物理内存,对于一个mem_segment会创建一个文件,并且mem_segment会和对应的文件进行映射。

1,对于legacy mode,DPDK系统会在hugetlbfs的挂载点上创建相应的内存文件。
2,对于dynamic mode,关于内存文件有两种形式:
若internal_config.in_memory(位于eal_internal_cfg.h)为true,则使用memfd_create(),或MAP_ANONYMOUS | MAP_HUGETLB 创建anonymous file。

若internal_config.in_memory(位于eal_internal_cfg.h)为false, 则在hugetlbfs的挂载点上创建相应的内存文件。

这样,DPDK系统能够通过一系列和文件相关的接口(比如open, close, fallocate, ftruncate等)对内存文件进行操作。

所以在dynamic mode下,DPDK向系统申请内存,其实就是通过fallocate, 或者ftruncate修改内存文件的大小;

从而获取更多的物理内存。而将内存归还给OS,就是使用unlink(), 删除对应的内存文件,释放文件所占用的物理内存。

从application的角度看,每次使用rte_malloc()申请内存时,DPDK会分配一个合适的malloc_elem管理这一段申请的内存(一个hugepage中可能包含一个或多个malloc_elem)。

而使用rte_free()释放内存时,就是将malloc_elem的状态设置为free,然后合并相邻的free malloc_elem即可。

五、总结
这篇文章简单地介绍了DPDK的内存管理和分配:
1、每一个malloc_heap都由一个由malloc_elem为节点的双向链表组成。
2、DPDK根据free malloc_elem所管理内存的大小将free malloc_elem划分到不同的free_head中。每次在分配内存时,可以快速地找到合适的free malloc_elem, 而不用遍历所有的free malloc_elem。采取的策略是首次适应算法(First Fit):从合适的free_head的头节点开始查找该表,把最先能够满足要求的空闲区分配给用户。
3、DPDK的内存管理的底层实现是通过memory-file,和相关的文件接口实现的。

六、函数调用图

下面给出的是内存管理和分配相关的代码的函数调用图:
1、malloc_elem : http://naotu.baidu.com/file/cda0a195d0f53d9a1c01052cedd91a3b?token=7100881a9cdcaf7e
2、malloc_heap :http://naotu.baidu.com/file/0617659be9481990d1e5c18986b0af32?token=227982f46fc62c42
3、eal_memalloc :http://naotu.baidu.com/file/39af99626733c35dad7850de8b4f11f9?token=07d7fb5bf46d49f6

如果您发现该资源为电子书等存在侵权的资源或对该资源描述不正确等,可点击“私信”按钮向作者进行反馈;如作者无回复可进行平台仲裁,我们会在第一时间进行处理!

评价 0 条
风晓L1
粉丝 1 资源 2038 + 关注 私信
最近热门资源
银河麒麟桌面操作系统备份用户数据  127
统信桌面专业版【全盘安装UOS系统】介绍  122
银河麒麟桌面操作系统安装佳能打印机驱动方法  114
银河麒麟桌面操作系统 V10-SP1用户密码修改  105
最近下载排行榜
银河麒麟桌面操作系统备份用户数据 0
统信桌面专业版【全盘安装UOS系统】介绍 0
银河麒麟桌面操作系统安装佳能打印机驱动方法 0
银河麒麟桌面操作系统 V10-SP1用户密码修改 0
作者收入月榜
1

prtyaa 收益393.62元

2

zlj141319 收益218元

3

1843880570 收益214.2元

4

IT-feng 收益209.03元

5

风晓 收益208.24元

6

777 收益172.71元

7

Fhawking 收益106.6元

8

信创来了 收益105.84元

9

克里斯蒂亚诺诺 收益91.08元

10

技术-小陈 收益79.5元

请使用微信扫码

加入交流群

请使用微信扫一扫!