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;
}
首先对参数进行基本的校验。
通过内存地址计算内存对象的地址。就是用待回收的地址和内存对像中的地址进行比较。如果相同,
然后校验地址是否有效。
最后将内存块对像加入列表尾部。