librte_malloc库提供了一套用于管理内存空间的API接口,它管理的内存是hugepages上创建出来的memzone,而不是系统的堆空间。通过这套接口,可以提高系统访问内存的命中率,防止了在使用Linux用户空间环境的4K页内存管理时容易出现TLB miss。
接口函数:void? rte_malloc( void ?ptr, size_t size, unsigned align ):用来替代malloc,从内存的huge_page中分配所需内存空间,分配的空间未被初始化。当size为0或者align不是2的整数倍的时候,,返回NULL。如果align为0,则对齐方式为任意长。若空间不足或者参数错误(size=0或者align不是2的整数倍)则函数返回NULL,若执行成功则返回分配的内存空间的起始地址。
void ?rte_zmalloc (const char?type, size_t size, unsigned align):和rte_malloc基本相同,只是额外将申请的内存空间初始化为0。若空间不足或者参数错误(size=0或者align不是2的整数倍)则函数返回NULL,若执行成功则返回分配的内存空间的起始地址。
void ?rte_calloc (const char?type, size_t num, size_t size, unsigned align):用来替代calloc,和rte_malloc基本相同,申请的总空间大小为num * size,申请了num个连续空间,每个空间的大小为size。内存空间初始化为0。若空间不足或者参数错误(size=0或者align不是2的整数倍)则函数返回NULL,若执行成功则返回分配的内存空间的起始地址。
void ?rte_realloc (void?ptr, size_t size, unsigned align):用来替代realloc,重新分配ptr指向的内存空间的大小。如果size为0,则释放此ptr指向空间。若空间不足或者参数错误(align不是2的整数倍)则函数返回NULL,若执行成功则返回分配的内存空间的起始地址。
int rte_malloc_validate (void?ptr, size_t?size):如果debug宏被打开,那么此函数会检查ptr指向的内存空间的header和trailer标记是否正常,如果正常则将这个空间的长度写入到size中。当ptr无效或者pte指向的内存空间有错误时,函数返回-1,否则返回0。
void rte_free( void ?ptr ):释放ptr指向的内存空间,和free函数基本一致。如果ptr为NULL,则不做任何改变。
void rte_malloc_dump_stats (const char?type):将指定的type的信息转存到控制台。如果type为NULL,则转存所有的内存type。
int rte_malloc_set_limit (const char?type, size_t max):设置type所能分配的最大内存。若执行成功则返回0,否则返回-1。
源码分析: rte_malloc()代码如下所示:
void * rte_malloc(const char *type, size_t size, unsigned align) { unsigned malloc_socket = malloc_get_numa_socket(); /* return NULL if size is 0 or alignment is not power-of-2 */ if (size == 0 || !rte_is_power_of_2(align)) return NULL; return malloc_heap_alloc(&malloc_heap[malloc_socket], type, size, align == 0 ? 1 : align); }主要包含两个函数调用:
- malloc_get_numa_socket():获取程序分配的socket的id。程序在哪个socket上运行,就从哪个socket上分配内存。
- malloc_heap_alloc():将传入的需要malloc的空间大小和align按照CACHE_LINE_SIZE做了对齐。
在rte_config.mem_config->malloc_heaps[]数组里,此socket对应的堆中,进行匹配,查找是否有合适内存可以分配。find_suitable_element()用来在堆中找到一块合适大小的内存,分配的内存是从堆的底部开始查找的。
struct malloc_elem *prev, *elem = find_suitable_element(heap, size, align, &prev);如果没有找到合适的空间,则需要调用malloc_heap_add_memzone()在rte_config.mem_config->memzone[]中给堆分配一块内存:
if (elem == NULL){ malloc_heap_add_memzone(heap, size, align); elem = find_suitable_element(heap, size, align, &prev); }调用malloc_elem_alloc()在堆中,将需要分配的内存划分出去。
if (elem != NULL) elem = malloc_elem_alloc(elem, size, align, prev);注意,在malloc_elem_alloc()中,采用的也是动态划分内存块的方式,即,如果当前适用于分配的内存块大于MALLOC_ELEM_OVERHEAD + MIN_DATA_SIZE,就会将这块内存拆分开,前一部分继续还放在原有的可用于分配的内存堆中,后一部分作为malloc的内存块。详见malloc_elem_alloc()函数。
rte_zmalloc()代码如下所示:
void * rte_zmalloc(const char *type, size_t size, unsigned align) { void *ptr = rte_malloc(type, size, align); if (ptr != NULL) memset(ptr, 0, size); return ptr; }直接调用的rte_malloc(),仅仅是做了memset处理,将分配的内存空间初始化为0。
rte_calloc()