C程序设计语言第八章内存分配向上取整

K&R C语言8.7节中有一个内存动态分配的代码,涉及到向上取整,最开始不懂为什么这样写,后来弄明白之后想把思路分享出来:

nunits = (nbytes + sizeof(Header) - 1) / sizeof(Header) + 1;

union Header base;        // 定义 base 变量
union Header *freep = NULL; // 空闲列表指针,初始为 NULL

void *malloc(unsigned nbytes) {
    Header *p, *prevp;
    Header *morecore(unsigned);
    unsigned nunits;

    // 第一次调用 malloc 时初始化
    if ((prevp = freep) == NULL) {
        base.s.ptr = freep = prevp = &base;
        base.s.size = 0;
    }

    // 计算所需的单元数,包括头部
    nunits = (nbytes + sizeof(Header) - 1) / sizeof(Header) + 1;

    // 遍历空闲列表找到合适的块
    for (p = prevp->s.ptr; ; prevp = p, p = p->s.ptr) {
        if (p->s.size >= nunits) {  // 找到足够大的块
            if (p->s.size == nunits) // 恰好大小相等
	            //当前块的下一个块赋给上一个块的下一个块,跳过了当前块
                prevp->s.ptr = p->s.ptr;
            else {                    // 分割块
                p->s.size -= nunits;
                //指针前移,指向分割后的新分配块的新位置
                p += p->s.size;
                p->s.size = nunits;
            }
            freep = prevp;
            //+1跳过头部信息,指向实际数据区
            return (void *)(p + 1);
        }
        if (p == freep)  // 没有找到合适的块
		    if ((p = morecore(nunits)) == NULL)
            return NULL;
    }
}

代码:

nunits = (nbytes + sizeof(Header) - 1) / sizeof(Header) + 1;

其中nunits是计算所需的内存块大小,nbytes是用户请求的字节数,sizeof(Header)是头部的大小,通常内存分配中除了用户请求的数据以外,还包括一些元数据,用于管理这些内存,其中包含指向下一个空闲块的指针以及该内存块的大小,它们被定义在头部Header中。且头部的大小通常被视为满足这种对齐要求。

这也就解释了为什么内存块数目的计算需要除头部的大小。

再看等式右边,(nbytes + sizeof(Header) - 1) / sizeof(Header) ,正常求内存块的大小一般会是nbytes / sizeof(Header),但是这种方式会被向下取整,与预期不符。

比如用户请求17个字节的内存大小,Header大小为817 / 8 = 2,实际上按照对齐要求,应该分配3个内存块才对。那么就考虑给nbytes加上一个Header的大小,即(nbytes + sizeof(Header)) / sizeof(Header)本例中就为(17 + 8) / 8 = 3,看到这里可能会想那为什么还要-1呢,不-1同样可以按照向下取整计算出正确的结果。

这个问题就要考虑到后面的+1操作了,+1是为了在请求到能容纳用户所需数据大小的块数目之外,还要保留一个Header的块,但是当用户请求的数据大小是Header大小的整数倍的话,比如用户请求24个字节,Header大小为8,那么按照不-1的情况来计算,(nbytes + sizeof(Header)) / sizeof(Header) + 1就是(24 + 8) / 8 + 1 = 5,实际上我们只需要4个内存块(三个数据块和一个Header块),-1就排除了这种情况的发生。

所以最终的公式就可以归纳为:

int n = (N - 1) / M + 1;

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值