Lenix固定长度内存分配源代码分析(草稿)

Lenix在给定的内存块中划分出两个部分

1、内存块对象区域。这部分用来将内存块构造成一个单向链表。这个属于管理空间,属于消耗空间。这个结构由于对象与存储空间分离,因此在存储空间出现了写越界,并不会造成管理结构的崩溃,可以保证系统正常运行。

2、内存块区域。实际可分配的空间

这里形成一个对应关系,可以从内存地址计算出内存块对象的地址。

在分配的时候,只需要从空闲队列中取出一个内存块,并返回其地址即可完成分配。算法复杂度为O(1)

在回收时,通过地址计算出内存块对象的地址,将内存块对象插入队列尾即可完成空间回收。算法复杂度为O(1)。

 

result_t    Fm_initial(fixed_mm_t * fm,void   * buffer,uint_t   size,int   grain)
{

    fixed_entry_t       *   fe;
    byte_t              *   buf;
    int                     i;

    /*
     *  管理的空间必须大于等于1024
     */
    if( size < 1024 )
        return RESULT_FAILED;

    FM_ZERO(fm);

    //  将粒度调整为64字节的整数倍,最小64字节,最大512字节
    grain = (grain + 63 ) / 64;
    if( grain > 8 ) grain = 8;
    if( grain <=0 ) grain = 1;
    grain *= 64;

    fe  = buffer;
    buf = (byte_t *)buffer + size;
    buf = (byte_t *)((uint_t  )buf & ~7); //  调整为8字节对齐,不算浪费

    
    /*  计算可以划分出的内存块数量  */
    for( ; (uint_t  )(fe + 1) < (uint_t  )(buf - grain) ; fe++,buf -= grain)
        fm->fm_max++;

    /*  初始化对象参数  */
    fe = buffer;
    fm->fm_head         = fe;
    fm->fm_tail         = fe;
    fm->fm_free         = fm->fm_max;
    fm->fm_size         = size;
    fm->fm_grain        = grain;
    fm->fm_fehead       = fe;
    fm->fm_buffer       = buf;

    /*  将空闲块组织成一个链表  */
    for( fe++,i = 1 ; i < fm->fm_max ; i++,fe++)
    {
        fm->fm_tail->fe_next    = fe;
        fm->fm_tail             = fe;
        fe->fe_next             = NULL;
    }
    
    return RESULT_SUCCEED;
}


要进行内存分配,首先要创建一个固定内存分配对象,提供一个缓冲区,以及需要的分配粒度作为参数。

Lenix首先对缓冲区的大小进行校验,小于1K的空间,Lenix认为不必使用内存管理机制,

然后对分配粒度进行调整,调整为8的整数倍,并对力度大小做了限制,最小分配64个字节,最大分配256个字节。

然后对缓冲区进行对齐处理,以保证每个内存块都是8字节对齐。

然后计算提供的缓冲区可以划分为多少个内存块,算法为内存块对象从缓冲区低地址开始计算,向高地址增长,内存块对象从缓冲区高地址开始计算,向低地址增长。当两个区域有重叠的时候停止。

利用计算得到的参数对内存分配对象进行初始化。

最后将内存块对象组织成为一个链表。

void    *   Fm_alloc(fixed_mm_t * fm)
{
    fixed_entry_t    *    fe;

    if( fm->fm_free < 1 )
        return NULL;

    fe = fm->fm_head;

    fm->fm_head = fe->fe_next;
    fm->fm_free--;

    if( 0 == fm->fm_free )
    {
        fm->fm_head = NULL;
        fm->fm_tail = NULL;
    }

    fe->fe_ptr = (fixed_entry_t *)((byte_t *)(fm->fm_buffer) + (fe - fm->fm_fehead) * fm->fm_grain);
    
    return fe->fe_ptr;
}


首先查看内存分配对象是否还有可分配的内存块,如果没有,返回0,分配失败。

取出分配列表的第一个内存块,并将列表头调整为下一个内存块。

递减可用内存块数量,如果可用内存块数量为0,则调整分配列表的头、尾指针。

计算出内存块的地址并保存在内存对象中,在回收时用作有效性校验。

返回分配到的内存地址。

 

result_t    Fm_free(fixed_mm_t * fm,void   * m)
{
    fixed_entry_t    *    fe;

    if( NULL == fm || NULL == m )
        return RESULT_FAILED;

    fe = FM_ATOFE(fm,m);

    //  内存块合法性校验
    if( fe->fe_ptr != (fixed_entry_t *)m )
        return RESULT_FAILED;

    if( 0 == fm->fm_free)
    {
        fm->fm_head    = fe;
        fm->fm_tail    = fe;
        fm->fm_free++;
        return RESULT_SUCCEED;
    }

    fe->fe_next             = NULL;
    fm->fm_tail->fe_next    = fe;
    fm->fm_tail             = fe;
    fm->fm_free++;
        
    return RESULT_SUCCEED;
}

 

首先对参数进行基本的校验。

通过内存地址计算内存对象的地址。就是用待回收的地址和内存对像中的地址进行比较。如果相同,

然后校验地址是否有效。

最后将内存块对像加入列表尾部。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值