上篇文章DPDK抓包工具dpdk-dumpcap的使用中讲到了dpdk-dumpcap抓包工具的用法,今天我们来看一下DPDK的内存池。
DPDK提供了内存池的接口,可以很方便地让我们进行内存节点的管理分配,但是如果使用不当,可能会造成很隐蔽的问题。
下面讲到的是DPDK内存池节点重复释放导致的问题。
主要测试代码如下:
void dpdk_mempool_test()
{
int rc = -1;
//申请两个节点,10个字节大小的内存池
struct rte_mempool *pool_id = (void *)rte_mempool_create("pool_test", 2, 10, 0, 0, NULL, NULL, NULL, NULL,
rte_socket_id(), MEMPOOL_F_NO_IOVA_CONTIG|MEMPOOL_F_SC_GET|MEMPOOL_F_SP_PUT);
void* mem1 = NULL;
rc = rte_mempool_get((struct rte_mempool *)pool_id, (void **)(&mem1));
if (rc == 0)
{
printf("mem1: %p\n", mem1);
}
void* mem2 = NULL;
rc = rte_mempool_get((struct rte_mempool *)pool_id, (void **)(&mem2));
if (rc == 0)
{
printf("mem2: %p\n", mem2);
}
//内存池只有两个节点,正常情况mem3取不到
void* mem3 = NULL;
rc = rte_mempool_get((struct rte_mempool *)pool_id, (void **)(&mem3));
if (rc == 0)
{
printf("mem3: %p\n", mem3);
}
rte_mempool_put(pool_id, mem1);
rte_mempool_put(pool_id, mem2);
rte_mempool_put(pool_id, mem1); //mem1释放两次
printf("\n");
void* mem4 = NULL;
rc = rte_mempool_get((struct rte_mempool *)pool_id, (void **)(&mem4));
if (rc == 0)
{
printf("mem4: %p\n", mem4);
}
void* mem5 = NULL;
rc = rte_mempool_get((struct rte_mempool *)pool_id, (void **)(&mem5));
if (rc == 0)
{
printf("mem5: %p\n", mem5);
}
//从mem6的地址可以看到,前面mem1的地址取到了两次
void* mem6 = NULL;
rc = rte_mempool_get((struct rte_mempool *)pool_id, (void **)(&mem6));
if (rc == 0)
{
printf("mem6: %p\n", mem6);
}
//mem7取不到
void* mem7 = NULL;
rc = rte_mempool_get((struct rte_mempool *)pool_id, (void **)(&mem7));
if (rc == 0)
{
printf("mem7: %p\n", mem7);
}
}
运行程序之后的打印:
通过打印可以看到,mem1如果被释放了两次,后面再去获取节点,会把mem1的地址取两次出来,导致的问题是:如果在多个线程中,同时从一个内存池取内存节点,有可能取到了同一个内存块进行操作,肯定会导致这个内存块的数据出现错乱,或者是同一个线程中,先把内存节点缓存起来,然后又从内存池中获取到了相同的内存节点进行操作,最后再对缓存的内存节点进行操作,这样也会导致内存块的数据出现错乱。
所以,我们在使用DPDK内存池时,为了避免这种问题出现,一定不能重复释放内存节点。
好了,关于DPDK需要注意的重复释放的问题就讲到这里了。
有问题的朋友,可以进网络技术开发交流群提问(先加我wx,备注加群)。喜欢文章内容的朋友,记得加个关注哦~~