DPDK17.02内存管理3 – rte_eal_memzone_init
该函数初始化memzone子系统,将其置空。同时将前面初始化的连续大页初始化为malloc heap。
1、清除所有的memzone
1 2 | mcfg->memzone_cnt = 0; memset(mcfg->memzone, 0, sizeof(mcfg->memzone)); |
2、调用 rte_eal_malloc_heap_init() 函数 初始化 malloc heap
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | int rte_eal_malloc_heap_init(void) { struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; unsigned ms_cnt; struct rte_memseg *ms; if (mcfg == NULL) return -1; /* 对每个 mcfg->memseg[i],将其关联到 mcfg->malloc_heaps[ms->socket_id] */ for (ms = &mcfg->memseg[0], ms_cnt = 0; (ms_cnt < RTE_MAX_MEMSEG) && (ms->len > 0); ms_cnt++, ms++) { malloc_heap_add_memseg(&mcfg->malloc_heaps[ms->socket_id], ms); } return 0; } |
3、调用 malloc_heap_add_memseg() 函数
将memseg添加到malloc heap中,每个NUMA node上包含一个 heap结构体,使我们可以根据线程运行所在的NUMA node,在对应的结点分配内存。
struct malloc_heap 结构体用来管理每个socket上的空闲空间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | static void malloc_heap_add_memseg(struct malloc_heap *heap, struct rte_memseg *ms) { /* 分配 struct malloc_elem 结构的内存块头,一个在起始位置,一个在结尾的位置 */ struct malloc_elem *start_elem = (struct malloc_elem *)ms->addr; /* MALLOC_ELEM_OVERHEAD 的值定义为 * (MALLOC_ELEM_HEADER_LEN + MALLOC_ELEM_TRAILER_LEN) * 即 struct malloc_elem 结构的大小,加上 MALLOC_ELEM_TRAILER_LEN * 如果是非Debug模式,MALLOC_ELEM_TRAILER_LEN 宏的值定义为0, * 否则为一个 cacheline 大小,即为memseg 内存块的尾部添加一个cookie空间。 */ struct malloc_elem *end_elem = RTE_PTR_ADD(ms->addr, ms->len - MALLOC_ELEM_OVERHEAD); end_elem = RTE_PTR_ALIGN_FLOOR(end_elem, RTE_CACHE_LINE_SIZE); const size_t elem_size = (uintptr_t)end_elem - (uintptr_t)start_elem; /* 初始化 start_elem */ malloc_elem_init(start_elem, heap, ms, elem_size); /* 初始化 end_elem,并指向 start_elem */ malloc_elem_mkend(end_elem, start_elem); /* 将这段连续内存通过 start_elem 插入到 elem->heap->free_head[i] 中 */ malloc_elem_free_list_insert(start_elem); heap->total_size += elem_size; } |
如下图所示。
3.1 malloc_elem_init() 函数
该函数初始化连续内存的头部 struct malloc_elem 结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | void malloc_elem_init(struct malloc_elem *elem, struct malloc_heap *heap, const struct rte_memseg *ms, size_t size) { elem->heap = heap; elem->ms = ms; elem->prev = NULL; memset(&elem->free_list, 0, sizeof(elem->free_list)); elem->state = ELEM_FREE; /* 初始为空闲状态 */ /* elem的大小保存在start_elem->size中,其值为end_elem - start_elem得到的值, * 所以这个大小中实际是包含着一个struct mealloc_elem结构大小的, * 并不是实际有效可用空间的大小 */ elem->size = size; elem->pad = 0; set_header(elem); /* 如果是DEBUG 模式编译,则设置头部的header_cookie */ set_trailer(elem); /* 如果是DEBUG 模式编译,则设置连续内存空间尾部的cookie */ } |
struct malloc_elem 结构体定义如下:
3.2 malloc_elem_mkend() 函数
该函数同样初始化一个 struct malloc_elem 结构,作为连续内存的尾部结构,并指向 start_elem:
1 2 3 4 5 6 | void malloc_elem_mkend(struct malloc_elem *elem, struct malloc_elem *prev) { malloc_elem_init(elem, prev->heap, prev->ms, 0); /* 初始化 malloc_elem 结构 */ elem->prev = prev; /* 指向 start_elem */ elem->state = ELEM_BUSY; /* 设置为非空闲,使其不会被合并 */ } |
3.3 malloc_elem_free_list_insert(start_elem)
该函数按这部分 memseg 连续内存空间的大小,将其插入到对应的 elem->heap->free_head[idx] 中,即 mcfg->malloc_heaps[ms->socket_id]->elem->heap->free_head[idx] 链表中。
1 2 3 4 5 6 7 8 | void malloc_elem_free_list_insert(struct malloc_elem *elem) { size_t idx; /* 根据给定的大小,计算其对应的 free_head[i] 索引 */ idx = malloc_elem_free_list_index(elem->size - MALLOC_ELEM_HEADER_LEN); elem->state = ELEM_FREE; LIST_INSERT_HEAD(&elem->heap->free_head[idx], elem, free_list); } |
根据内存的大小,系统将其插入到对应的队列中,通过malloc_elem_free_list_index()函数将heaps中的malloc_elem元素按大小分为不同的组,分别为:
1 2 3 4 5 6 7 8 9 10 11 12 13 | heap->free_head[0] - (0 , 2^8] heap->free_head[1] - (2^8 , 2^10] heap->free_head[2] - (2^10 ,2^12] heap->free_head[3] - (2^12, 2^14] heap->free_head[4] - (2^14, 2^16] heap->free_head[5] - (2^16, 2^18] heap->free_head[6] - (2^18, 2^20] heap->free_head[7] - (2^20, 2^22] heap->free_head[8] - (2^22, 2^24] heap->free_head[9] - (2^24, 2^26] heap->free_head[10] - (2^26, 2^28] heap->free_head[11] - (2^28, 2^30] heap->free_head[12] - (2^30, MAX_SIZE] |
————————————————————
原创文章,转载请注明: 转载自孙希栋的博客