C语言的内存管理,从来都是一个让人头秃的问题。要想更自由地管理内存,就必须去堆中申请,然后还需要考虑何时释放,万一释放不当,或者没有及时释放,造成的后果都是难以估量的。
当然如果就这些,那倒也还不算什么。问题就在于,如果大量地使用malloc和free函数来申请内存,首先使要经历一个从应用层切入系统内核层,调用完成之后,再返回应用层的一系列步骤,实际上使非常浪费时间的。更重要的是,还会产生大量的内存碎片。比如,先申请了一个1KB的空间,紧接着又申请了一个8KB的空间。而后,这个1KB使用完了,被释放,但是这个空间却只有等到下一次有刚好1KB的空间申请,才能够被重新调用。这么一来,极限情况下,整个堆有可能被弄得支离破碎,最终导致大量内存浪费。
那么这种情况下,我们解决这类问题的思路,就是创建一个内存池。
内存池,实际上就是我们让程序创建出来的一块额外的缓存区域,如果有需要释放内存,先不必使用free函数,如果内存池有空,那么直接放入内存池。同样的道理,下一次程序申请空间的时候,先检查下内存池里面有没有合适的内存,如果有,则直接拿出来调用,如果没有,那么再使用malloc。
其实内存池我们就可以使用单链表来进行维护,下面通过一个通讯录的程序来说明内存池的运用。
普通的版本:
- //Example 04 V1
- #include
- #include
- #include
- 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("联系人:%sn", person->name);
- printf("电话:%sn", 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
- #include
- #include
- #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("联系人:%sn", person->name);
- printf("电话:%sn", 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;
- }