dpdk内存管理——rte_malloc实现

DPDK以两种方式对外提供内存管理方法,一个是rte_mempool,主要用于网卡数据包的收发;一个是rte_malloc,主要为应用程序提供内存使用接口。这里我们主要讲一下rte_malloc函数。

rte_malloc实现的大体流程如下图所示。
在这里插入图片描述
下面我们逐个函数分析。

rte_malloc
/*
 * Allocate memory on default heap.
 */
void *
rte_malloc(const char *type, size_t size, unsigned align)
{
         return rte_malloc_socket(type, size, align, SOCKET_ID_ANY);
}

这个函数没什么可说的,直接调用rte_malloc_socket,但注意传入的socketid参数为SOCKET_ID_ANY。

rte_malloc_socket

从这个函数的入口检查可以看出,如果传入的分配内存大小size为0或对其align不是2次方的倍数就返回NULL

void *
rte_malloc_socket(const char *type, size_t size, unsigned align, int socket_arg)
{
         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
         int socket, i;
         void *ret;
 
         /* return NULL if size is 0 or alignment is not power-of-2 */
         if (size == 0 || (align && !rte_is_power_of_2(align)))
                   return NULL;
 
         if (!rte_eal_has_hugepages())
                   socket_arg = SOCKET_ID_ANY;
    /*如果传入的socket参数为SOCKET_ID_ANY ,则会先尝试在当前socket上分配内存*/
         if (socket_arg == SOCKET_ID_ANY)
                   socket = malloc_get_numa_socket(); /*获取当前socket_id*/
         else
                   socket = socket_arg;
 
         /* Check socket parameter */
         if (socket >= RTE_MAX_NUMA_NODES)
                   return NULL;
    /*尝试在当前socket上分配内存,如果分配成功则返回*/
         ret = malloc_heap_alloc(&mcfg->malloc_heaps[socket], type,
                                     size, 0, align == 0 ? 1 : align, 0);
         if (ret != NULL || socket_arg != SOCKET_ID_ANY)
                   return ret;
    /*尝试在其他socket上分配内存,直到分配成功或者所有socket都尝试失败*/
         /* try other heaps */
         for (i = 0; i < RTE_MAX_NUMA_NODES; i++) {
                   /* we already tried this one */
                   if (i == socket)
                            continue;
 
                   ret = malloc_heap_alloc(&mcfg->malloc_heaps[i], type,
                                               size, 0, align == 0 ? 1 : align, 0);
                   if (ret != NULL)
                            return ret;
         }
 
         return NULL;
}

到这里我们可以得到一个结论,在开启NUMA时rte_malloc会优先在当前socket上分配内存,如果分配失败再尝试在其他socket上分配内存。

malloc_heap_alloc

这个函数用来模拟从heap中(也就是struct malloc_heap)分配内存,其调用逻辑图如下:

void *
malloc_heap_alloc(struct malloc_heap *heap,
                   const char *type __attribute__((unused)), size_t size, unsigned flags,
                   size_t align, size_t bound)
{
         struct malloc_elem *elem;
    /*将size调整为cache line对齐*/
         size = RTE_CACHE_LINE_ROUNDUP(size);
         align = RTE_CACHE_LINE_ROUNDUP(align);
 
         rte_spinlock_lock(&heap->lock);
    /*找到合适的malloc_elem结构*/
         elem = find_suitable_element(heap, size, flags, align, bound);
         if (elem != NULL) {
                   elem = malloc_elem_alloc(elem, size, align, bound);
                   /* increase heap's count of allocated elements */
                   heap->alloc_count++; /*计数加一*/
         }
         rte_spinlock_unlock(&heap->lock);
 
         return elem == NULL ? NULL : (void *)(&elem[1]);
}

注意最后的返回值,返回的是elem[1]的地址,而不是elem的地址。elem[1]是什么呢?其实就是elem+1。说的直观点,rte_malloc其实就是分配了一个内存块,也可以说是分配了一个malloc_elem,这个malloc_elem作为这个内存块的一部分(存放在开头),相当于这个内存块的描述符,真正可以使用的内存是malloc_elem之后的内存区域。如下图所示。
在这里插入图片描述

在补一张内存初始化中讲到的数据结构关系图。
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值