单链表、内存池应用-消息抑制表的应用

1.消息抑制表

设备之间进行源源不断的收和发送的时候,为保证数据的不丢包,由于延迟,拥塞或者其他情况,往往需要超时重发,大数据的交互,有这样一种需求:为保证消息的唯一性,需要对对一个消息的接受进行判断,判断是否对刚接收到消息进行处理或者进行抑制(直接丢掉不处理);

因为是海量大数据,需要对接收到的每一条消息进行建表动态缓存---即消息抑制表;

建表过程,分几种情况(没有绝对性,仅供参考)

(1)如果消息的生命周期很短(消息完成使命的时间) ,辨识信息短       可以数组来记录

(2)如果辨识信息较大-占用内存大,可以使用malloc动态分配和free释放

(3)如果消息生命周期长,辨识信息较大-;频繁(我是5ms)动态申请内存,造成碎片就不合适,需要使用内存池来进行

2.内存池

内存池的使用,可以为系统稳定性带来好处,有名的案例是Nginx服务器---低内存/高并发的性能,其中使用了双向链表+内存池的行为;
双向链表的好处,是在表中进行删除的时候非常方便--O(1)的复杂度;当然也有弊端(因此也有人用堆来做)
内存池的好处是,是在有限的内存中实现最大利用,避免了系统内存碎片!

3.具体实现(测试代码见最后)

在程序中使用内存时,都由内存池进行分配,不再使用的内存交给内存池回收,用于再次分配。

内存池一般会有如下的接口:
memory_pool_init, memory_pool_malloc, memory_pool_free 和 memory_pool_destroy;
内存池结构:

  • Memory_Pool: 用于内存属性结构,用于整个内存池的管理
  • Memory_Map_Table: 内存映射表,是Memory的映射,用于管理Memory
  • Memory_Alloc_Table: 内存分配表,用于记录分配过的内存
  • Memory:实际用于分配的内存

为辅助看懂我的代码,如下是我所使用的具体内存池布局:

定义的数据结构(队列节点和队列的定义)

我要做的功能,要根据情况,根据入队信息进行匹配,匹配成功,踢出内存池;否则内存池要根据更新情况,自动的出队和入队
定义内存池中队列数量为5的测试情况,验证:
 
68-78-88-98-a8内存的出入队的变化;验证情况有效!
具体代码(可以直接点击链接---下载测试工程):

 mem_pool.h

#ifndef __MEMORY_POOL_H__
#define __MEMORY_POOL_H__
 
#define MAX_POOL_SIZE 1024 * 1024
#define  BLOCK_SIZE 16
// #define BLOCK_SIZE 12//64
 
typedef struct memory_map_talbe
{
	char *p_block;
	int index;
	int used;
} Memory_Map_Table;//Memory_Map_Table: 内存映射表,是Memory的映射,用于管理Memory
 
typedef struct memory_alloc_table
{
	char *p_start;
	int used;
	int block_start_index;	//块首地址
	int block_cnt;
}Memory_Alloc_Table;//Memory_Alloc_Table: 内存分配表,用于记录分配过的内存
 
typedef struct memory_pool
{
	char *memory_start;					//内存池起始地址, free整个内存池时使用
	Memory_Alloc_Table *alloc_table;//用于记录分配过的内存
	Memory_Map_Table *map_table;	//用于管理Memory
	int total_size;				//内存池的总数量
	int internal_total_size;
	int increment;
	int used_size;				//内存池已用的数量
	int block_size;
	int block_cnt;
	int alloc_cnt;//分配数量
} Memory_Pool;//Memory_Pool: 用于内存属性结构,用于整个内存池的管理
 
extern Memory_Pool *memory_pool_init(int size, int increment);
extern void *Memory_malloc(Memory_Pool *pool, int size);
extern void memory_free(Memory_Pool *pool, void *memory);
extern void memory_pool_destroy(Memory_Pool *pool);
 
#endif

 tab_queue.h

#ifndef __TAB_QUEUE__
#define __TAB_QUEUE__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <arpa/inet.h>
#define MAX_QUEUE_NUM 1000
#define base_queue_insert_head(h, x)		\
	(x)->next = (h)->next;			\
	(x)->next->prev = x;			\
	(x)->prev = h;				\
	(h)->next = x
typedef struct {
    __uint32_t time;    //0->....
    __uint8_t source_id;//0-64
    __uint8_t obj_id;   //0-8
    __uint8_t flag;     //0 1
    __uint8_t res;     //0 1
    // __uint32_t timeout;
    // __uint8_t date[16];
}OBJ_STRU;
#define ElemType OBJ_STRU
typedef struct QNode
{
    // char *memory;
    ElemType data;//定义队列中的元素
    struct QNode *next;
}QNode;
 
typedef struct LinkQueue
{
    QNode *front;
    QNode *rear;
}LinkQueue;//定义一个队列,队列只有一个头指针和一个尾指针
void InitQueue(LinkQueue *q);
int QueueLength(LinkQueue Q);
void *FindElem(LinkQueue *Q, ElemType e);
// int FindElem(LinkQueue *Q, ElemType e);
void InsertQueue(LinkQueue *p,ElemType *e);
void DeleteQueue(LinkQueue *p,ElemType *e);
void DestoryQueue(LinkQueue *p);
int QueueTraverse(LinkQueue Q);

#endif // !__TAB_QUEUE__

 mem_pool.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include "mem_pool.h"
//获取内存映射表的位置
Memory_Map_Table *map_table_pos(Memory_Pool *pool)
{
	Memory_Map_Table *p = (Memory_Map_Table *)(pool->memory_start + sizeof(Memory_Pool));
	return p;
}
//获取内存分配表的位置
Memory_Alloc_Table *alloc_talbe_pos(Memory_Pool *pool)
{
	Memory_Alloc_Table *p = (Memory_Alloc_Table *)(pool->memory_start + sizeof(Memory_Pool) +
			sizeof(Memory_Map_Table) * (pool->block_cnt));
	return p;
} 

//获得memory在位置
char *memory_pos(Memory_Pool *pool)
{
	char *p = (char *)(pool->memory_start + sizeof(Memory_Pool) +
			(sizeof(Memory_Map_Table) + sizeof(Memory_Alloc_Table))* pool->block_cnt);
	return p;
}
 
Memory_Pool *memory_pool_init(int size, int increment)
{
	char *p = NULL;
	char *p_memory = NULL;
	Memory_Pool *pool = NULL;
	Memory_Alloc_Table *alloc_table = NULL;
	Memory_Alloc_Table *p_alloc_table = NULL;
	Memory_Map_Table *map_table = NULL;	
	Memory_Map_Table *p_map_table = NULL;
	int block_cnt = 0;
	int all_size = 0;
	int i = 0;
 
	if (size < 0 || size > MAX_POOL_SIZE) {
		printf("memory_pool_init(): Invalid size(%d)\n", size);
		return pool;
	}
 
	block_cnt = ((size + BLOCK_SIZE - 1) / BLOCK_SIZE);
	all_size = sizeof(Memory_Pool) + (sizeof(Memory_Map_Table) +sizeof(Memory_Alloc_Table)) * block_cnt + size;
	p = (char *)malloc(all_size);
	if (p == NULL) 
	{
		perror("Malloc failed\n");
		return pool;
	}
 
	memset(p, 0, all_size);
 
	pool = (Memory_Pool *)p;		//内存池的首地址
	pool->block_cnt = block_cnt;	//块数
	pool->block_size = BLOCK_SIZE;	//每个块大小
	pool->increment = increment;	//每块间增加大小
	pool->internal_total_size = BLOCK_SIZE * block_cnt;//每个块大小 * 每块间增加大小 =全部增加的大小
	pool->total_size = size;		//块总大小
	pool->used_size = 0;
	pool->alloc_cnt = 0;
	pool->memory_start = p;
 
	p_memory = memory_pos(pool);
	map_table = map_table_pos(pool);
	for (i = 0; i < block_cnt; i++) 
    {
		p_map_table = (Memory_Map_Table *)((char *)map_table + i * sizeof(Memory_Map_Table));
		p_map_table->index = 0;
		p_map_table->p_block = p_memory + i * BLOCK_SIZE;
		p_map_table->used = 0;
	}
 
	alloc_table = alloc_talbe_pos(pool);
	for (i = 0; i < block_cnt; i++) 
    {
		p_alloc_table = (Memory_Alloc_Table *)((char *)alloc_table + i * sizeof(Memory_Alloc_Table));
		p_alloc_table->block_cnt = 0;
		p_alloc_table->block_start_index = -1;
		p_alloc_table->p_start = NULL;
		p_alloc_table->used = 0;
	}
 
	printf("memory_pool_init: total size: %d, block cnt: %d, block size: %d\n",
			pool->total_size, pool->block_cnt, BLOCK_SIZE);
	return pool;
}
 
void *Memory_malloc(Memory_Pool *pool, int size)
{
	char *p_start = NULL;
	int need_block_cnt = 0;
	Memory_Map_Table *map_table = NULL;
	Memory_Map_Table *p_map_table = NULL;
	Memory_Alloc_Table *alloc_table = NULL;
	Memory_Alloc_Table *p_alloc_table = NULL;
	int block_cnt = 0;
	int start_index = -1;
	int i = 0;
 
	if (size <= 0) 
	{
		printf("Invalid size(%d)\n", size);
		return p_start;
	}
 
	if (size > pool->total_size) 
	{
		printf("%d is more than total size\n", size);
		return p_start;
	}
 
	if (size > pool->total_size - pool->used_size) 
	{
		printf("Free memory(%d) is less than allocate(%d)\n",
		pool->total_size - pool->used_size, size);
		return NULL;
	}
 
	need_block_cnt = (size + BLOCK_SIZE - 1) / BLOCK_SIZE;//需要分配的总块数
	map_table = map_table_pos(pool);
	printf("nend_cnt=%d\n",need_block_cnt);
	start_index = -1;
	for (i = 0; i < pool->block_cnt; i++) 
	{
		p_map_table = (Memory_Map_Table *)((char *)map_table + i * sizeof(Memory_Map_Table));
		if (p_map_table->used) 
		{
			printf("before alloc: map index: %d is used\n", i);
			block_cnt = 0;
			start_index = -1;
			continue;
		}
 
		if (start_index == -1) 
		{
			start_index = i;
			//printf("start_index: %d\n", start_index);
		}
		block_cnt++;
 
		if (block_cnt == need_block_cnt) 
		{
			break;
		}
	}
 
	if (start_index == -1) 
	{
		printf("No available memory to used\n");
		return NULL;
	}
 
	alloc_table = alloc_talbe_pos(pool);
 
	for (i = 0; i < pool->block_cnt; i++) {
		p_alloc_table = (Memory_Alloc_Table *)((char *)alloc_table + i * sizeof(Memory_Alloc_Table));
		if (p_alloc_table->used == 0) {
			break;
		}
		p_alloc_table = NULL;
	}
 
	if (p_alloc_table == NULL) {
		return NULL;
	}
	p_map_table = (Memory_Map_Table *)((char *)map_table + sizeof(Memory_Map_Table) * start_index);
	p_alloc_table->p_start = p_map_table->p_block;
	p_alloc_table->block_start_index = start_index;//p_map_table->index;
	p_alloc_table->block_cnt = block_cnt;
	p_alloc_table->used = 1;
 
	//printf("block cnt is %d\n", block_cnt);
	for (i = start_index; i < start_index + block_cnt; i++) {
		p_map_table = (Memory_Map_Table *)((char *)map_table + i * sizeof(Memory_Map_Table));
		//printf("map index: %d is used\n", i);
		p_map_table->used = 1;
	}
 
	printf("Alloc size: %d, Block: (start: %d, end: %d, cnt: %d)\n", size,
			start_index, start_index + block_cnt - 1, block_cnt);
	pool->alloc_cnt++;
	pool->used_size += size;
	return p_alloc_table->p_start;
}
 //将pool中memeory处的内存释放
void memory_free(Memory_Pool *pool, void *memory)
{
	Memory_Map_Table *map_table = NULL;
	Memory_Map_Table *p_map_table = NULL;
	Memory_Alloc_Table *alloc_table = NULL;
	Memory_Alloc_Table *p_alloc_table = NULL;
	int i = 0;
	int block_start_index = 0;
	int block_cnt = 0;
 
	if (memory == NULL) {
		printf("memory_free(): memory is NULL\n");
		return;
	}
 
	if (pool == NULL) {
		printf("Pool is NULL\n");
		return;
	}
 
	alloc_table = alloc_talbe_pos(pool);
 	printf("pool当前分配数量=%d  \n",pool->alloc_cnt);
	for (i = 0; i < pool->alloc_cnt; i++) //
	{
		p_alloc_table = (Memory_Alloc_Table *)((char *)(alloc_table) + i * sizeof(Memory_Alloc_Table));
		if (p_alloc_table->p_start == memory) 
		{
			block_start_index = p_alloc_table->block_start_index;
			block_cnt = p_alloc_table->block_cnt;
			p_alloc_table->used =0;
			pool->alloc_cnt --;
		}
		printf("s=%p \n",p_alloc_table->p_start);
	}
 
	if (block_cnt == 0) //遍历分配表,找不到
	{
		printf("error in [%s]:mem=%p,block_cnt = 0,free none!\n",__func__,memory);
		return;
	}
 
	map_table = map_table_pos(pool);
 
	printf("Block: free: start: %d, end: %d, cnt: %d\n", block_start_index,
			block_start_index + block_cnt -1, block_cnt);

	for (i = block_start_index; i < block_start_index + block_cnt; i++) 
	{
		p_map_table = (Memory_Map_Table *)((char *)map_table + i * sizeof(Memory_Map_Table));
		p_map_table->used = 0;
	}
 
	p_alloc_table->used = 0;
	pool->used_size -= block_cnt * BLOCK_SIZE;
}
 
void memory_pool_destroy(Memory_Pool *pool)
{
	if (pool == NULL) {
		printf("memory_pool_destroy: pool is NULL\n");
		return;
	}
 
	free(pool);
	pool = NULL;
}
 
// main.c:
// #include <stdio.h>
 
// #include "memory_pool.h"
 
#if 0
#define LOOP 5
#define ALLOC_SIZE 8
 
int main(void)
{
	Memory_Pool *pool = NULL;
	char *p1 = NULL;
	char *p2 = NULL;
	int i = 0;
 
	
 
	pool = memory_pool_init(1024, 512);
	if (pool == NULL)
		printf("memory pool init failed\n");
 
	for (i = 0; i < 2; i++) 
    {
		p1 = (char *)Memory_malloc(pool, ALLOC_SIZE);
		if (p1 == NULL)
			printf("Malloc failed\n");
		else
			printf("Malloc success\n");
 
		// memory_free(pool, p1);
	}
 
 
	p1 = (char *)Memory_malloc(pool, 256);
	if (p1 == NULL)
		printf("Malloc failed\n");
	else
		printf("Malloc success\n");
 
	p2 = (char *)Memory_malloc(pool, 512);
	if (p1 == NULL)
		printf("Malloc failed\n");
	else
		printf("Malloc success\n");
 
	memory_free(pool, p1);
    
 
	p1 = (char *)Memory_malloc(pool, 256);
	if (p1 == NULL)
		printf("Malloc failed\n");
	else
		printf("Malloc success\n");
 
	memory_pool_destroy(pool);
 
	return 0;
}
#endif

 tab_queue.c

#include "tab_queue.h"
#include "mem_pool.h"
#define ALLOC_SIZE 16
#define CNT_MP 10//1000
#define MP_SIZE ( CNT_MP* ALLOC_SIZE)
static Memory_Pool *pool = NULL;
//队列的初始化
void InitQueue(LinkQueue *q)
{
    // q->front = (LinkQueue*)malloc(sizeof(QNode));
    
    pool = memory_pool_init(MP_SIZE,ALLOC_SIZE);//
    
    q->front = (QNode*)Memory_malloc(pool,sizeof(QNode));
    // printf("1===%ld",sizeof(QNode));
    if(!q->front)
    {
        printf("存储分配失败 !\n");
        return;
    }
    q->rear = q->front;
    q->front->next = NULL;
}
/* 求队列的长度 */
int QueueLength(LinkQueue Q)
{ 
	int i=0;
	QNode *p=Q.front;
	while(Q.rear!=p)
	{
		 i++;
		 p=p->next;
	}
	return i;
}
 //查找元素
void *FindElem(LinkQueue *Q, ElemType e)
{
	if (Q->front == Q->rear)
		return NULL;
    if((Q== NULL))     return 0;   
	QNode *p = Q->front->next;
    QNode *f =p;
    uint16_t i=0;
	while (p)
	{
		// if (p->data == e)
        if((p->data.time == e.time)&&(p->data.source_id == e.source_id)&&(p->data.obj_id == e.obj_id))
        {
            // return 1;//成功返回1
            return f;
        }
		else
		{
            f =p;
			p = p->next;
            i++;
		}
	}
	return NULL;//失败返回0
}
//队列的插入
void InsertQueue(LinkQueue *p,ElemType *e)
//队列为p,要插入的元素为e,队列的rear指针指向队列的最后一个元素。队列的front指针指向头结点,头结点无元素
{
    // QNode *ptr= (QNode*)malloc(sizeof(QNode));
    QNode *spf=p->front->next;
    QNode *ptr= (QNode *)Memory_malloc(pool,sizeof(QNode));
    ptr->next= NULL;
    printf("insert:%p;p->f=%p;",ptr,p->front->next);
    if(ptr ==NULL) /* 存储分配失败 */
    {
        printf("存储分配失败 in [%s] !\n",__func__);
        return ;
    }

    ptr->data = *e;;
    p->rear->next = ptr;
    p->rear = p->rear->next;
    p->rear = ptr;
    
    // p->front->next = spf;
    printf("spf=%p,p->f=%p, p->r=%p \n",spf,p->front->next,p->rear);
}
 
//队列的删除
void DeleteQueue(LinkQueue *p,ElemType *e)
{
    QNode *s;
    if(p->front == p->rear)
    {
        return;
    }
    s = p->front->next;
    *e = s->data;
    p->front->next = s->next;
    // p->front->next = p->front->next;
    //   if(s == p->rear)
    
    if(p->front->next == NULL)//用这条也可以是等价的
    {
        p->front = p->rear;
    }
    printf("del%p;p->f=%p, p->r=%p \n",s,p->front->next,p->rear);
    // memory_free(pool,(QNode *) &(e->time));
    memory_free(pool,s);
    // free(s);
}
 
//销毁一个队列
void DestoryQueue(LinkQueue *p)
{
    
    while(p->front)
    {
        p->rear = p->front->next;//p->front->next == NULL
        memory_free(pool, p->front);
        // free(p->front);//释放p的头结点
        p->front = p->rear;//把p的front和rear都置为NULL
    }
 
}
/* 从队头到队尾依次对队列Q中每个元素输出 */
int QueueTraverse(LinkQueue Q)
{
	QNode * p;
	p=Q.front->next;
    if(p == NULL)
        printf("null queue!\n");
	while(p)
	{
		//  visit(p->data);
         printf("%p:%d,%02x,%02x\n",p,p->data.time,p->data.source_id,p->data.obj_id);
		 p=p->next;
	}
	printf("\n");
	return 1;
}
#if 1
int main()
{
#if 0
    int i,len = 0;
    LinkQueue p;
    ElemType e={};
    char d,c;
    InitQueue(&p);
    printf("输入字符串:\n");
    scanf("%c",&d);
    while(c != '#')
    {
        InsertQueue(&p,&c);
        len++;
        scanf("%c",&c);
    }
    printf("len=%d\n",QueueLength(p));
    if(FindElem(&p,d) ==1)
        printf("get sucess!\n");
    printf("字符串为:\n");
    for(i = 1;i <= len;i++)
    {
        DeleteQueue(&p,&e);
        printf("%c",e);
    }
#else
    int i;
    LinkQueue p;
    ElemType *pe;
    ElemType ie;
    ElemType e;
    InitQueue(&p);
    for(i = 1;i <= 1;i++)
    {
        ie.time =i; 
        ie.source_id = i/2;
        ie.obj_id =i%5;
        InsertQueue(&p,&ie);
    }
    printf("len=%d\n",QueueLength(p));
    
    QueueTraverse(p);
    ie.time=3;ie.source_id=9;ie.obj_id=3;
    pe = (ElemType *)FindElem(&p,ie);
    printf("pp=%p\n",pe);
    if(pe)
    {
        printf("get sucess===!\n");
        printf("get1:%02x,%02x,%02x\n",pe->time,pe->source_id,pe->obj_id);
        DeleteQueue((LinkQueue *)&(pe),&e);
        QueueTraverse(p);
        printf("len=%d,",QueueLength(p));
        printf("del:%02x,%02x,%02x\n",e.time,e.source_id,e.obj_id);
    }    
    else
    {
        printf("get fail====!\n");
        ie.time=2;
        InsertQueue(&p,&ie);
    }
    // DeleteQueue(&p,&e);
    // QueueTraverse(p);
    // printf("len=%d\n",QueueLength(p));
    //     printf("del:%02x,%02x,%02x\n",e.time,e.source_id,e.obj_id);

    ie.time=2;
     printf("=============len=%d===========\n",QueueLength(p));
    int len ;
    while(1)
    {
        len = QueueLength(p);
        printf("len =%d \n",len);
        if(len>=(CNT_MP-1))
        {
            DeleteQueue(&(p),&e);
            // DeleteQueue(&(p),&ie);
        }
        QueueTraverse(p);    
        ie.time++;
        usleep(10*1000);
        InsertQueue(&p,&ie);
        
    }
    return 0;
    #endif
}
#endif

 Makefile文件,根据编译器--修改自己的编译cc

.SUFFIXES : .x .o .c .s

# CC := arm-linux-gcc
CC=     $(shell which gcc)
# STRIP := arm-linux-strip

#TARGET = tcp_demo
#SRCS := gpio_demo.c
#TARGET = crc
#SRCS := crc.c
# TARGET = tab_queue
# SRCS := tab_queue.c
TARGET = que_pool
SRCS := mem_pool.c \
		tab_queue.c
all: 
	$(CC) -static $(SRCS) -o $(TARGET) -g
# $(STRIP) $(TARGET) 
	
# cp -va $(TARGET) /nfsroot/
clean:
	rm -f *.o 
	rm -f *.x 
	rm -f *.flat
	rm -f *.map
	rm -f temp
	rm -f *.img
	rm -f $(TARGET)	
	rm -f *.gdb
	rm -f *.bak

测试结果:

参考博客:
基于Linux C内存池的实现(纯代码演示) - 知乎

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xiaoxilang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值