设为首页 加入收藏

TOP

C学习笔记――malloc内存分配(二)
2014-11-23 19:14:56 来源: 作者: 【 】 浏览:46
Tags:学习 笔记 malloc 内存 分配
描,节省时间*/ return (void *)(p+1); /*返回去头部单元的空闲空间*/ } if(p == freep) /*闭环的空闲链表,第一次调用malloc申请,或扫描一遍,未发现足够大的空间*/ if((p = morecore(nunits)) == NULL) /*向系统申请空间*/ return NULL; /*未申请成功,*/ } }

通过下面的morecore()和free()函数的程序分析可知,在向系统成功申请空间后,p将指向有足够空间的空闲块。但在此代码中,进入下一此空闲块扫描前,p将指向下一块不足的空闲块,导致多扫描了一遍。个人觉得,如果空间足够,可以多申请一个静态指针beforefreep,指向freep的前一个空闲块。这样上面代码可添加一句,提高效率:

if(p == freep){ /*这样要添加大括号*/
if((p = morecore(nunits)) == NULL)
		return NULL;
	p = beforefreep;
}
或
if(p == freep) /*这里可以不用加大括号,else与最近的if匹配*/
if((p = morecore(nunits)) == NULL)
		return NULL;
	else
p = beforefreep;

向系统申请空间的时,不是按需分配,而是有一个最小申请单元数。让您足够用,这次用不完可以留着下次用,不用每次都向系统申请,又不会系统浪费空间。

真正向系统申请空间,还需调用系统调用sbrk(n)(UNIX下),若申请成功,该指针返回指向n个字节的存储空间;若申请失败,返回-1(不是NULL)。返回的指针类型是char *(应该是最小的存储空间单元)。

#define NALLOC 1024	/*最小申请单元数*/

/*morecore函数:向系统申请更多的存储空间*/
static Header *morecore(unsigned nu)	/*返回的是静态空闲块链表指针*/
{
	char *cp, *sbrk(int);
	Header *up;

	if(nu < NALLOC)
		nu =NALLOC;
	cp = sbrk(nu * sizeof(Header));	/*调用系统调用申请系统空间*/
	if(cp == (char *) -1)
		return NULL;	/*申请失败,没有空间*/
	up = (Header *)cp;	/*转换为Header*指针类型*/
	up->s.size = nu;	/*设置此空间块的大小*/
	free((void *)(up +1));	/*释放空间*/
	return freep;	
}

这里的返回的freep,在free中更新了,才返回的。当初也想过既然freep都是静态全局变量了,那这里为什么还要返回一个静态变量呢,直接在函数里赋值就好了。其实这里有成功与失败,所以程序来需要判断申请结果,而且返回的freep是与申请最相关东西。

free(void *ap)函数就是释放指针ap所指的空间,具体要释放的大小在ap前一个指针,即头部信息里。释放主要就是为了把此空间插入到空闲块链表中。所以要找到此空间块两边的空闲块(也有可能只有一块空闲块,即入口base)。然后判断是否与前一块相连,与后一块相连,相连的话,合并成一块,否则直接在中间插入一个新的空闲块链表。

/*free函数:释放ap,将ap块放入空闲链表中*/
void free(void *ap)
{
	Header *p, *bp;

	bp =(Header *)ap -1;	/*指向ap块的头部*/
	for(p = freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr)	/*找到bp所在空闲链表中的位置*/
		if(p >= p->s.ptr && (bp > p || bp < p->s.ptr))	/*判断是否在链表的开头或末尾*/
			break;

	if(bp + bp->s.size == p->s.ptr){	/*先判断能否与高地址的空闲块合并,即与后一块合并*/
		bp->s.size += p->s.ptr->s.size;
		bp->s.ptr = p->s.ptr->s.ptr;
	}
	else
		bp->s.ptr = p->s.ptr;	/*不能合并,bp指向后一块地址*/

	if(p + p->s.size == bp){	/*再判断能否与地地址的空闲块合并,即与前一块合并*/
		p->s.size += bp->s.size;
		p->s.ptr = bp->s.ptr;
	}
	else
		p->s.ptr =bp;	/*不能合并,p指向bp地址*/
	freep =p;
}

注:中文版翻译的又有歧义了,原著分别是“join to upper nbr”和“jointo lower nbr”。

\

\

这个free程序,处理的太妙了。一般思维,先与前一块合并,再与下一块合并,如下面的程序(显然比我的好多了):

	if(p + p->s.size == bp){	/*与前一块相连?*/
		if(bp + bp->s.size == p->s.ptr){	/*与后一块相连?*/
			p->s.size += bp->s.size + p->s.ptr->s.size;
			p->s.ptr = p->s.ptr->s.ptr;
		}else
			p->s.size += bp->s.size;
	}else{
		if(bp + bp->s.size == p->s.ptr){	/*与后一块相连?*/
			bp->s.size += p->s.ptr->s.size;
			bp->s.ptr = p->s.ptr->s.ptr;
			p->s.ptr = bp;
		}else	/*不与任何一块相连*/
			bp->s.ptr = p->s.ptr;
			p->s.ptr = bp;
	}

从这里可以看出,通过malloc申请后的空间,并没有初始化,所以在使用前记得初始化,不小心当做右值使用,出错的概率很大。

《C程序设计语言》(第2版 新版)不愧是经典,值得细读和巩固。感谢作者!

写了很久才写完,有错误或不好的地方,欢迎各位指正和批评!也感谢您花时间阅读



首页 上一页 1 2 下一页 尾页 2/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇Objective-C基础笔记(3)OC的内.. 下一篇C语言笔试题精选2---int a[10];问..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: