打印
[技术手册]

C语言的内存池使用

[复制链接]
80|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
jf101|  楼主 | 2024-4-7 16:25 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式


C语言的内存管理,从来都是一个让人头秃的问题。要想更自由地管理内存,就必须去堆中申请,然后还需要考虑何时释放,万一释放不当,或者没有及时释放,造成的后果都是难以估量的。

当然如果就这些,那倒也还不算什么。问题就在于,如果大量地使用malloc和free函数来申请内存,首先使要经历一个从应用层切入系统内核层,调用完成之后,再返回应用层的一系列步骤,实际上使非常浪费时间的。更重要的是,还会产生大量的内存碎片。比如,先申请了一个1KB的空间,紧接着又申请了一个8KB的空间。而后,这个1KB使用完了,被释放,但是这个空间却只有等到下一次有刚好1KB的空间申请,才能够被重新调用。这么一来,极限情况下,整个堆有可能被弄得支离破碎,最终导致大量内存浪费。

那么这种情况下,我们解决这类问题的思路,就是创建一个内存池。

内存池,实际上就是我们让程序创建出来的一块额外的缓存区域,如果有需要释放内存,先不必使用free函数,如果内存池有空,那么直接放入内存池。同样的道理,下一次程序申请空间的时候,先检查下内存池里面有没有合适的内存,如果有,则直接拿出来调用,如果没有,那么再使用malloc。

其实内存池我们就可以使用单链表来进行维护,下面通过一个通讯录的程序来说明内存池的运用。

普通的版本:

//Example 04 V1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct Person
{
char name[40];
char phone[20];
struct Person* next;
};

void getInput(struct Person* person);
void printPerson(struct Person* person);
void addPerson(struct Person** contects);
void changePerson(struct Person* contacts);
void delPerson(struct Person** contacts);
struct Person* findPerson(struct Person* contacts);
void displayContacts(struct Person* contacts);
void releaseContacts(struct Person** contacts);

void getInput(struct Person* person)
{
printf("请输入姓名:");
scanf("%s", person->name);
printf("请输入电话:");
scanf("%s", person->phone);
}

void addPerson(struct Person** contacts)
{
struct Person* person;
struct Person* temp;

person = (struct Person*)malloc(sizeof(struct Person));
if (person == NULL)
{
  printf("内存分配失败!\n");
  exit(1);
}

getInput(person);

//将person添加到通讯录中
if (*contacts != NULL)
{
  temp = *contacts;
  *contacts = person;
  person->next = temp;
}
else
{
  *contacts = person;
  person->next = NULL;
}
}

void printPerson(struct Person* person)
{
printf("联系人:%s\n", person->name);
printf("电话:%s\n", person->phone);
}

struct Person* findPerson(struct Person* contacts)
{
struct Person* current;
char input[40];

printf("请输入联系人:");
scanf("%s", input);

current = contacts;
while (current != NULL && strcmp(current->name, input))
{
  current = current->next;
}

return current;
}

void changePerson(struct Person* contacts)
{
struct Person* person;

person = findPerson(contacts);
if (person == NULL)
{
  printf("找不到联系人!\n");
}
else
{
  printf("请输入联系电话:");
  scanf("%s", person->phone);
}
}

void delPerson(struct Person** contacts)
{
struct Person* person;
struct Person* current;
struct Person* previous;

//先找到待删除的节点的指针
person = findPerson(*contacts);
if (person == NULL)
{
  printf("找不到该联系人!\n");
}
else
{
  current = *contacts;
  previous = NULL;

  //将current定位到待删除的节点
  while (current != NULL && current != person)
  {
   previous = current;
   current = current->next;
  }

  if (previous == NULL)
  {
   //若待删除的是第一个节点
   *contacts = current->next;
  }
  else
  {
   //若待删除的不是第一个节点
   previous->next = current->next;
  }

  free(person);//将内存空间释放
}
}

void displayContacts(struct Person* contacts)
{
struct Person* current;

current = contacts;
while (current != NULL)
{
  printPerson(current);
  current = current->next;
}
}

void releaseContacts(struct Person** contacts)
{
struct Person* temp;

while (*contacts != NULL)
{
  temp = *contacts;
  *contacts = (*contacts)->next;
  free(temp);
}
}

int main(void)
{
int code;
struct Person* contacts = NULL;
struct Person* person;

printf("| 欢迎使用通讯录管理程序 |\n");
printf("|--- 1:插入新的联系人 ---|\n");
printf("|--- 2:查找现有联系人 ---|\n");
printf("|--- 3:更改现有联系人 ---|\n");
printf("|--- 4:删除现有联系人 ---|\n");
printf("|--- 5:显示当前通讯录 ---|\n");
printf("|--- 6:退出通讯录程序 ---|\n");

while (1)
{
  printf("\n请输入指令代码:");
  scanf("%d", &code);
  switch (code)
  {
  case 1:addPerson(&contacts); break;
  case 2:person = findPerson(contacts);
   if (person == NULL)
   {
    printf("找不到该联系人!\n");
   }
   else
   {
    printPerson(person);
   }
   break;
  case 3:changePerson(contacts); break;
  case 4:delPerson(&contacts); break;
  case 5:displayContacts(contacts); break;
  case 6:goto END;
  }
}

END://此处直接跳出恒循环
releaseContacts(&contacts);

return 0;

}

运行结果如下:

//Consequence 04 V1
| 欢迎使用通讯录管理程序 |
|--- 1:插入新的联系人 ---|
|--- 2:查找现有联系人 ---|
|--- 3:更改现有联系人 ---|
|--- 4:删除现有联系人 ---|
|--- 5:显示当前通讯录 ---|
|--- 6:退出通讯录程序 ---|

请输入指令代码:1
请输入姓名:HarrisWilde
请输入电话:0101111

请输入指令代码:1
请输入姓名:Jack
请输入电话:0101112

请输入指令代码:1
请输入姓名:Rose
请输入电话:0101113

请输入指令代码:2
请输入联系人:HarrisWilde
联系人:HarrisWilde
电话:0101111

请输入指令代码:2
请输入联系人:Mike
找不到该联系人!

请输入指令代码:5
联系人:Rose
电话:0101113
联系人:Jack
电话:0101112
联系人:HarrisWilde
电话:0101111

请输入指令代码:3
请输入联系人:HarrisWilde
请输入联系电话:0101234

请输入指令代码:5
联系人:Rose
电话:0101113
联系人:Jack
电话:0101112
联系人:HarrisWilde
电话:0101234

请输入指令代码:6

下面加入内存池:

//Example 04 V2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX 1024

struct Person
{
char name[40];
char phone[20];
struct Person* next;
};

struct Person* pool = NULL;
int count;

void getInput(struct Person* person);
void printPerson(struct Person* person);
void addPerson(struct Person** contects);
void changePerson(struct Person* contacts);
void delPerson(struct Person** contacts);
struct Person* findPerson(struct Person* contacts);
void displayContacts(struct Person* contacts);
void releaseContacts(struct Person** contacts);
void releasePool(void);

void getInput(struct Person* person)
{
printf("请输入姓名:");
scanf("%s", person->name);
printf("请输入电话:");
scanf("%s", person->phone);
}

void addPerson(struct Person** contacts)
{
struct Person* person;
struct Person* temp;

//如果内存池不是空的,那么首先从里面获取空间
if (pool != NULL)
{
  person = pool;
  pool = pool->next;
  count--;
}
//内存池为空,则直接申请
else
{
  person = (struct Person*)malloc(sizeof(struct Person));
  if (person == NULL)
  {
   printf("内存分配失败!\n");
   exit(1);
  }
}


getInput(person);

//将person添加到通讯录中
if (*contacts != NULL)
{
  temp = *contacts;
  *contacts = person;
  person->next = temp;
}
else
{
  *contacts = person;
  person->next = NULL;
}
}

void printPerson(struct Person* person)
{
printf("联系人:%s\n", person->name);
printf("电话:%s\n", person->phone);
}

struct Person* findPerson(struct Person* contacts)
{
struct Person* current;
char input[40];

printf("请输入联系人:");
scanf("%s", input);

current = contacts;
while (current != NULL && strcmp(current->name, input))
{
  current = current->next;
}

return current;
}

void changePerson(struct Person* contacts)
{
struct Person* person;

person = findPerson(contacts);
if (person == NULL)
{
  printf("找不到联系人!\n");
}
else
{
  printf("请输入联系电话:");
  scanf("%s", person->phone);
}
}

void delPerson(struct Person** contacts)
{
struct Person* person;
struct Person* current;
struct Person* previous;
struct Person* temp;
{

};

//先找到待删除的节点的指针
person = findPerson(*contacts);
if (person == NULL)
{
  printf("找不到该联系人!\n");
}
else
{
  current = *contacts;
  previous = NULL;

  //将current定位到待删除的节点
  while (current != NULL && current != person)
  {
   previous = current;
   current = current->next;
  }

  if (previous == NULL)
  {
   //若待删除的是第一个节点
   *contacts = current->next;
  }
  else
  {
   //若待删除的不是第一个节点
   previous->next = current->next;
  }

  //判断内存池中有没有空位
  if (count < MAX)
  {
   //使用头插法将person指向的空间插入内存池中
   if (pool != NULL)
   {
    temp = pool;
    pool = person;
    person->next = temp;
   }
   else
   {
    pool = person;
    person->next = NULL;
   }
   count++;
  }
  //没有空位,直接释放
  else
  {
   free(person);//将内存空间释放
  }
}
}

void displayContacts(struct Person* contacts)
{
struct Person* current;

current = contacts;
while (current != NULL)
{
  printPerson(current);
  current = current->next;
}
}

void releaseContacts(struct Person** contacts)
{
struct Person* temp;

while (*contacts != NULL)
{
  temp = *contacts;
  *contacts = (*contacts)->next;
  free(temp);
}
}

void releasePool(void)
{
struct Person* temp;
while (pool != NULL)
{
  temp = pool;
  pool = pool->next;
  free(temp);
}
}

int main(void)
{
int code;
struct Person* contacts = NULL;
struct Person* person;

printf("| 欢迎使用通讯录管理程序 |\n");
printf("|--- 1:插入新的联系人 ---|\n");
printf("|--- 2:查找现有联系人 ---|\n");
printf("|--- 3:更改现有联系人 ---|\n");
printf("|--- 4:删除现有联系人 ---|\n");
printf("|--- 5:显示当前通讯录 ---|\n");
printf("|--- 6:退出通讯录程序 ---|\n");

while (1)
{
  printf("\n请输入指令代码:");
  scanf("%d", &code);
  switch (code)
  {
  case 1:addPerson(&contacts); break;
  case 2:person = findPerson(contacts);
   if (person == NULL)
   {
    printf("找不到该联系人!\n");
   }
   else
   {
    printPerson(person);
   }
   break;
  case 3:changePerson(contacts); break;
  case 4:delPerson(&contacts); break;
  case 5:displayContacts(contacts); break;
  case 6:goto END;
  }
}

END://此处直接跳出恒循环
releaseContacts(&contacts);
releasePool();

return 0;

}

使用特权

评论回复
沙发
中国龙芯CDX| | 2024-4-10 10:51 | 只看该作者
楼主这个管理系统项目很不错,深入了解一下

使用特权

评论回复
板凳
szt1993| | 2024-4-10 11:25 | 只看该作者
内存池,实际上就是我们让程序创建出来的一块额外的缓存区域,如果有需要释放内存,先不必使用free函数,如果内存池有空,那么直接放入内存池。

使用特权

评论回复
地板
小夏天的大西瓜| | 2024-4-11 17:25 | 只看该作者
确实申请和释放内存对于整体的程序设计非常重要

使用特权

评论回复
5
jf101|  楼主 | 2024-4-14 14:25 | 只看该作者
内存池使用单链表来进行维护,非常实用

使用特权

评论回复
6
小小蚂蚁举千斤| | 2024-4-15 10:04 | 只看该作者
自由地管理内存就必须去堆中申请,然后还需要考虑何时释放

使用特权

评论回复
7
OKAKAKO| | 2024-4-19 18:41 | 只看该作者
内存池,实际上就是我们让程序创建出来的一块额外的缓存区域,如果有需要释放内存,先不必使用free函数,如果内存池有空,那么直接放入内存池。

使用特权

评论回复
8
星辰大海不退缩| | 2024-4-21 12:29 | 只看该作者
这个管理系统项目适合新学习C语言的新手

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

184

主题

1220

帖子

2

粉丝