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内存池的实现(纯代码演示) - 知乎