C语言c语言中的内存管理问题

简单内存池的实现(C语言)
第一次写技术博客,呵呵,谢谢师兄的建议,很好的想法,希望以后有更多的东西记录。
以前完全不知道内存池,听师兄说过之后就开始了解了。刚开始练手还是遇到了很多问题,在师兄的讲解下终于还是完成了第一次的小小练习,很开心,再接再厉!!下面我内存池的设计文档和相关代码介绍如下:
设计文档:
1.内存池是用来干什么的
可以避免频繁的小块内存分配导致内存碎片
在用户层和操作系统层之间的一层,使得内存分配更稳定
分配速度更快
2.总体设计
二个层次,chunk管理层和slot分配器层,分别作为与操作系统接口和用户分配接口
chunk管理?
chunk数据结构设计。每个chunk大小为1KB。通过链表链接起来。
有个全局head指针指向第一个chunk,以便到最后释放内存
chunk块的插入使用头插法
每个chunk中还需要保存的信息必须有:
当前chunk中的可用空间首地址/指向下一chunk指针
slot数据结构设计
每一级slot大小是上一级slot大小的两倍。从4字节开始,一共9级
4B,8B,16B,32B,64B,128B,256B,512B,1024B
有个slot的表,它是一个指针数组,指向各级slot的头指针
3.用户接口:
void Pool_Init
//首次使用内存池时初始化
void *Pool_Alloc(int size)
//分配函数
void *Pool_Free(void *ptr)
//释放函数
Pool_release()&//不再使用内存池后释放
4.详细设计
考虑分配出去的内存,需要保存哪些信息才能被回收?
要记录它们在哪一个slot!
设计分配出去的数据结构
struct slot *
struct slot* slots[9];
考虑如何才能把slot管理起来?
设计slot数据结构
如果用户申请一块内存u
&4B,从第一级slot分配
4B~8B,从第二级slot分配
8B~16B,从第三级slot分配…
512B~1K,从第九级slot分配…
大于1K,直接调用操作系统的malloc。
具体代码如下:
mempool.h文件内容:
#include&stdlib.h&
&& static const int
N=9;//C++风格。浪费空间
struct chunk{
&char *freeSp;
&struct chunk *
struct slot{
&struct slot *
static struct slot * slots[N];//注意static的使用,设置作用域,加强安全性
static struct chunk * chunk_head = NULL;
static void *chunk_alloc(int size,char tag){
&void *//记录分配的起始地址
&if(chunk_head-&freeSp+size+1
& (char*)chunk_head+1024){//注意此处偏移量,细节解决成败耶
&&struct chunk *c;
&&c=(struct chunk
*)malloc(1024);
&&c-&freeSp=(char
*)c+sizeof(struct chunk);//菜鸟都不注意这个小问题
&&c-&freeSp[0]=
&&c-&next=chunk_
&&chunk_head=c;
&ret=chunk_head-&freeSp+1;//加1的重要性
&chunk_head-&freeSp[0]=&
&chunk_head-&freeSp=chunk_head-&freeSp+size+1;
&printf("allocate from chunk!\n");
void Pool_Init(){
&for(i=0;i&N;i++){
&&slots[i]=NULL;
&chunk_head=(struct chunk *)malloc(1024);
&chunk_head-&freeSp=(char
*)chunk_head+sizeof(struct chunk);
&chunk_head-&next=NULL;
void *Pool_Alloc(int size){
&int SIZE=4;
&for(i=0;i&N-1;i++){
&&if(size&=SIZE)
&&SIZE=SIZE&&1;//左移相当于乘法运算
&if(i&N-1){
&&if(slots[i]!=NULL){
&&&ret=slots[i];
&&&slots[i]=slots[i]-&
&&&printf("allocate
from slot %d!\n",i);
chunk_alloc(size,i);//注意此处return,调试结果告诉我return&很重要,回到起点
&else if(i==N-1){
&&if(size&=1024-sizeof(struct
chunk)-1){//判断条件很重要,想清楚
&&&if(slots[i]!=NULL){
&&&&ret=slots[i];
&&&&slots[i]=slots[i]-&
&&&&printf("allocate
from slot %d!\n",i);
&&&&return
&&&&return
chunk_alloc(size,i);
&&&char *p=(char
*)malloc(size+1);//注意加1了哦,亲
&&&p[0]=9;
&&&ret=p+1;//同上
&&&printf("allocate
direct from malloc!\n");
void Pool_Free(void *ptr){//有些情况释放的时候加入slot队列,不是真正地释放内存空间
&char *p=(char *)ptr-1;//小技巧,1代表offset
&tag=p[0];
&switch(tag){//分情况讨论要详细
&&free(p);
&&((struct slot
*)ptr)-&next=slots[tag];
&&slots[tag]=(struct slot
void Pool_Release(){//不需要释放slot,因为slot指向的就是chunk空间,chunk
release了slot也就没了
&struct chunk *
&ck=chunk_head-&
&while(ck){//不容忽视
&&chunk_head-&next=ck-&
&&free(ck);
&&ck=chunk_head-&
&free(chunk_head);
main.c文件内容:
#include&stdio.h&
#include "mempool.h"
main(){//要多角度测试,总觉得数据不够,求数据!!
&Pool_Init();
&void *a,*b,*c,*d,*e,*f,*g;
&a=Pool_Alloc(1);
&b=Pool_Alloc(5);
&c=Pool_Alloc(15);
&d=Pool_Alloc(33);
&e=Pool_Alloc(65);
&f=Pool_Alloc(533);
&g=Pool_Alloc(2);
&Pool_Free(g);
&g=Pool_Alloc(3);
&Pool_Free(g);
&g=Pool_Alloc(7);
&Pool_Free(g);
&g=Pool_Alloc(8);
&Pool_Free(g);
&g=Pool_Alloc(3);
&Pool_Free(g);
&g=Pool_Alloc(34);
&Pool_Free(g);
&g=Pool_Alloc(35);
&Pool_Free(g);
&g=Pool_Alloc(511);
&Pool_Free(g);
&g=Pool_Alloc(510);
&Pool_Free(g);
&g=Pool_Alloc(519);
&Pool_Free(g);
&g=Pool_Alloc(520);
&Pool_Free(g);
&g=Pool_Alloc(880);
&Pool_Free(g);
&g=Pool_Alloc(878);
&Pool_Free(g);
&g=Pool_Alloc(1030);
&Pool_Free(g);
&g=Pool_Alloc(1033);
&Pool_Free(g);
&Pool_Release();
&return 0;
编程乃人生一细活,不是人人都能做好的。这需要时间和耐心。希望以后有更大的突破。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。天极传媒:天极网全国分站
您现在的位置: &&
水滴石穿C语言之内存使用
天极网 10:37
  问题:使用  有人写了一个将整数转换为字符串的函数:
char *itoa (int n){ char retbuf[20]; sprintf(retbuf, "%d", n); }  如果我调用这个函数:char *str5 = itoa(5),str5会是什么结果呢?  答案分析:  答案是不确定,可以确定的是肯定不是我们想要的 “5”。   retbuf定义在函数体中,是一个局部变量,它的内存空间位于栈(stack)中的某个位置,其作用范围也仅限于在itoa()这个函数中。当itoa()函数退出时,retbuf在调用栈中的内容将被收回,这时,这块内存地址可能存放别的内容。因此将retbuf这个局部变量返回给调用者是达不到预期的目的的。  那么如何解决这个问题呢,不用担心,方法不但有,而且还不止一个,下面就来阐述三种能解决这个问题的办法:  1)、在itoa()函数内部定义一个static char retbuf[20],根据静态变量的特性,我们知道,这可以保证函数返回后retbuf的空间不会被收回,原因是函数内的静态变量并不是放在栈中,而是放在程序中一个叫“.bss”段的地方,这个地方的内容是不会因为函数退出而被收回的。  这种办法确实能解决问题,但是这种办法同时也导致了itoa()函数变成了一个不可重入的函数(即不能保证相同的输入肯定有相同的输出),另外, retbuf [] 中的内容会被下一次的调用结果所替代,这种办法不值得推荐。  2)、在itoa()函数内部用malloc() 为retbuf申请内存,并将结果存放其中,然后将retbuf返回给调用者。由于此时retbuf位于堆(heap)中,也不会随着函数返回而释放,因此可以达到我们的目的。  但是有这样一种情况需要注意:itoa()函数的调用者在不需要retbuf的时候必须把它释放,否则就造成内存泄漏了,如果此函数和调用函数都是同一个人所写,问题不大,但如果不是,则比较容易会疏漏此释放内存的操作。  3)、将函数定义为char *itoa(int n, char *retbuf),且retbuf的空间由调用者申请和释放,itoa()只是将转换结果存放到retbuf而已。  这种办法明显比第一、二种方法要好,既避免了方法1对函数的影响,也避免了方法2对内存分配释放的影响,是目前一种比较通行的做法。  扩展分析:  其实就这个问题本身而言,我想大家都可以立刻想到答案,关键在于对内存这种敏感资源的正确和合理地利用,下面对内存做一个简单的分析:  1)、程序中有不同的内存段,包括:  .data - 已初始化全局/静态变量,在整个软件执行过程中有效;  .bss - 未初始化全局/静态变量,在整个软件执行过程中有效;  .stack - 函数调用栈,其中的内容在函数执行期间有效,并由编译器负责分配和收回;  .heap - 堆,由程序显式分配和收回,如果不收回就是内存泄漏。  2)、自己使用的内存最好还是自己申请和释放。  这可以说是一个内存分配和释放的原则,比如说上面解决办法的第二种,由itoa()分配的内存,最后由调用者释放,就不是一个很好的办法,还不如用第三种,由调用者自己申请和释放。另外这个原则还有一层意思是说:如果你要使用一个指针,最好先确信它已经指向合法内存区了,如果没有就得自己分配,要不就是非法指针访问。很多程序的致命错误都是访问一个没有指向合法内存区的指针,这也包括空指针。
(作者:楚云风责任编辑:方舟)
欢迎在新浪微博上关注我们
笔记本手机数码家电
document.write("");

我要回帖

更多关于 c语言内存怎么管理的 的文章

 

随机推荐