huyc

导航

内存池和数据移动

问题:

(a)请编写实现malloc()内存分配函数功能一样的代码。 
(b)给出一个函数来复制两个字符串A和B。字符串A的后几个字节和字符串B的前几个字节重叠。

想法:

1.malloc的分配算法已经N多人研究过了,基于链表的内存池性能不太好,但算法简单,有三种,首次适配,下次适配,最佳适配;基于桶的内存池将等价类映射到桶里面,查找性能较好,据说对桶应用首次适配就可以达到渐进最优的内存利用率。

2.如果没理解错,字符串A和B具有相同部分,需要复制类似于abcd,cdef这样的两个字符串,并且要求合并相同部分以得出abcdef。

实现:

1.基于链表的存储池,内存小时性能有点太差,可以体会下产生大量碎片时的程序性能。

#include <stdio.h>
#include <stdlib.h>
const int BFSZ = 4096; //性能太差时改下这里
typedef unsigned long pval_t; //与指针一样长的数据类型,不大不小,正好要放得下
static char pool_buf[BFSZ];
//这个跟《C程序设计语言》里面介绍的那个不同,实现方式也不太一样,整个存储池的信息保存在len中,next存放的是空节点的地址而非下一个,因此也没必要加入分配标识,代码仅维护可用的节点列表
//而且,x64环境下,void *是以8字节边界对齐的,long double据说是16位边界对齐
//总之,以两个计算机字长对齐,最苛刻的对齐条件
typedef struct ADT_unit{
struct ADT_unit *next;
pval_t len;
} pool_hdr, pool_unit;
static pool_hdr *pool_freep; //这个存放的是最后一次分配的位置,用于下次适配,希望没有理解错
const size_t gapsz = sizeof(pool_unit);
void display(){
pool_hdr *hdr;
char *p = pool_buf;
int i = 0;
printf("------STATUS-------, cfreep:%p, len:%d\n", pool_freep, pool_freep->len);
while(p < pool_buf+BFSZ){
hdr = (pool_hdr *)p;
printf("%d! %p -> %p: ", i++, hdr, hdr->next);
if(hdr->next){
printf("block free, ");
}else{
printf("block used, ");
}
printf("len: %d, space: %d\n", hdr->len, hdr->len - gapsz);
p += hdr->len;
}
printf("------ENDS-------\n");
}
void pool_init(){
pool_hdr *hdr = (pool_hdr *)pool_buf;
hdr->next = hdr;
hdr->len = BFSZ;
pool_freep = hdr;
}
static void pool_merger(){
pool_hdr *fp = 0, *cp, *np, *frp;
char *p = pool_buf;
//找到第一个空闲节点,将乱七八糟的链表重新排序了下
while(p < (char *)pool_buf + BFSZ){
cp = (pool_hdr *)p;
p += cp->len;
if(!cp->next){
continue;
}
fp = cp;
frp = fp;
pool_freep = fp;
break;
}
while(p < (char *)pool_buf + BFSZ){
cp = (pool_hdr *)p;
if(!cp->next){
p += cp->len;
continue;
}
if((char *)fp + fp->len == p){
fp->len += cp->len;//合并
}else{
fp->next = cp;
fp = cp;
}
p += cp->len;
}
fp->next = frp;
}
void *pool_alloc(size_t sz){
pool_unit *cp = 0, *np = pool_freep, *fp, *p;
size_t space;
size_t gap2 = gapsz << 1;
do{ //查找节点
fp = cp;
cp = np;
space = cp->len > gap2 ? cp->len - gap2 : 0; //一小时debug的成果,防止溢出
np = (pool_unit *)cp->next;
}while(space < sz && np != pool_freep);
if(space < sz){ //查找失败,合并空闲区域,再次查找节点
pool_merger();
cp = 0;
np = pool_freep;
do{
fp = cp;
cp = np;
space = cp->len > gap2 ? cp->len - gap2 : 0;
np = (pool_unit *)cp->next;
}while(space < sz && np != pool_freep);
}
if(space < sz){
return 0;
}else{
p = cp + 1 + (sz+gapsz-1)/gapsz;
p->len = cp->len - ((char *)p - (char *)cp);
cp->len -= p->len; //增加节点
cp->next = p;
p->next = np;
fp = fp ? fp:p; //删除节点,更新前驱
fp->next = p;
cp->next = 0;
pool_freep = p;
return cp+1;
}
}
void pool_dealloc(void *p){ //添加节点
if(p){
pool_hdr *hdr = (pool_hdr *)p - 1, *cp = pool_freep;
hdr->next = cp->next;
cp->next = hdr;
}else{
printf("warning: NULL\n");
}
}

int main(){
void *p1[10], *p2;
int i, j;
pool_init();
p2 = pool_alloc(3);
display();
for(i = 0; i < 10000; ++i){
for(j = 0; j < 10; ++j){
p1[j] = pool_alloc(rand()%128);
}
for(j = 0; j < 10; ++j){
pool_dealloc(p1[j]);
}
}
display();
return 0;
}

2.字符串拷贝

#include <stdio.h>
/*
* 如果a短一些,则如此匹配: aaaa
* bbbbbb
* 如果b短一些,则如此匹配: aaaaaa
* bbbb
* 如果一样长,则对齐匹配: aaaaaa
* bbbbbb
*/
void copy_abtoc(char *c, int sc, const char *a, int sa, const char *b, int sb){
int aorb = sa - sb, i, j, left, len;
const char *ba, *bb;
if(aorb < 0){
left = 0;
len = sa-1; //不计尾符'\0'
}else if(aorb > 0){
left = sa - sb;
len = sb-1;
}else{
left = 0;
len = sb-1;
}
ba = a+left;
bb = b;
int match;
for(i = 0; i < len; ++i){
if(ba[i] != *bb){
++left;
continue;
}
match = 1;
for(j = 1; j < len - i; ++j){
if(ba[i+j] == bb[j]){
continue;
}
match = 0;
break;
}
if(match){
break;
}
}
for(i = 0; i < left; ++i){
if(i < sc)
c[i] = a[i];
else
return;
}
for(i = 0; i < sb; ++i){
if(i < sc)
c[left+i] = b[i];
else
return;
}
}
int main(){
char a[] = "abdedef", b[] = "dedefgh", c[32];
copy_abtoc(c, sizeof c, a, sizeof a, b, sizeof b);
printf("%s\n", c);
return 0;
}




posted on 2011-10-13 20:37  huyc  阅读(405)  评论(0)    收藏  举报