linux0.11分析之内存分配(结合uCos和VxWorks)

 

看了Linux0.11mallocfree函数实现,很有感触,存储桶的概念以前没有接触过,我觉得很经典,至少在结构和设计上,让人喜欢。至于性能等其它方面众多的考虑,我想结合目前熟悉的uCosVxWorks来谈一谈。

首先看Linux0.11的存储桶原理及实现。桶很容易让人想到数组,先看下面几个数据结构。

下图这个是存储桶描述符数据结构定义,描述一个存储桶。从图片中各个字段的描述中就可以明白个大概了,page指向一个页面,指向的这个页面就是一个存储桶,这个页面(桶)被分为一个个相同大小的块,块大小由bucket_size给定,freeptr指向桶中空闲内存位置,即指向桶中空闲的块,可以猜到,桶中的块应该是由链表练起来了(这个很多系统中都这个实现),refcnt一个引用计数,即桶中分配出去的块数目,next字段显然就是让桶描述构成一个链条。

(声明,本文图来自《Linux0.11内核完全注释》)

 

下面再看一个存储桶目录数据结构,以及目录数组。

不同大小的目录指向不同存储桶大小的描述符,每种存储桶大小的描述符可以用链表链起来,这样内存分配就不会受到限制了。整体结构如下图。

 

现在存储桶原理已经很清晰了,最后再看一张空闲存储桶描述符链表结构指针。

刚开始malloc的时候,会用一页内存建立上面这样一个空闲存储桶描述符链表,这样,当需要用到存储桶描述符的时候(当为某一种大小的存储桶再申请一页内存供分配的时候就再需要一个存储桶描述符)或者存储桶描述符使用完毕的时候(当一个存储桶中所有块都被释放掉的时候,这个存储桶(页面)就需要被释放,这个存储桶描述符就需要回收)可以从链表中得到(释放)一个存储桶描述符。

最后说一点就是malloc的时候对于指定内存size,会搜索存储桶目录从小到大,直到找到第一个大于size的存储桶目录项,然后在这个存储桶目录项对应的存储桶中分配一块空间。

 

到了这里,相信mallocfree的流程就已经可以想象了。

 

uCos是短小精悍的嵌入式OS,对于内存管理和分配的实现比较简单,这是由嵌入式OS的特性决定的,嵌入式系统中对于内存的控制更多的是留给用户自身。

具体讲解之前,先说一下嵌入式OS中经常说到的MemPart的概念,字面上可以理解为内存分区,和硬盘分区完全两个概念,内存分区就是把一整块内存分成很多区,每次内存分配和释放都对应在某个区中分配内存和释放内存。分区管理是嵌入式OS常用的策略。

uCos也是采用分区管理,对于每一个分区,uCos都有一个数据结构OS_MEM来描述这个内存区,uCos的一个内存分区相当于Linux0.11的一个存储桶,内存分区在创建的时候被分为指定块数和大小的一个个块,用同样的链表形式链接起来,创建内存分区过程具体见下面的函数描述。uCos在系统初始化的时候会初始化一个空闲内存分区描述块链表,创建一个内存分区的时候就会从中取走一个空闲的描述块,释放一个内存分区的时候同样就回收描述块。

关于内存分区描述块,下面贴出两个数据结构。

typedef struct {                                    /*MEMORY    CONTROL                   BLOCK */

    void   *OSMemAddr;              /* Pointer to beginning of memory partition */

    void   *OSMemFreeList;     /* Pointer to list of free memory blocks */

    INT32U  OSMemBlkSize;   /* Size (in bytes) of each block of memory*/

    INT32U  OSMemNBlks;    /* Total number of blocks in this partition*/

    INT32U  OSMemNFree;         /* Number of memory blocks remaining inthis partition*/

} OS_MEM;

上面的内存分区描述块,uCos注释中称之为内存控制块也很贴切。

 

OS_EXT  OS_MEM *OSMemFreeList;   

/* Pointer to free list ofmemory partitions*/

OS_EXT  OS_MEM OSMemTbl[OS_MAX_MEM_PART];

/* Storage for memory partition manager*/

         上面的是内存分区描述块空闲指针和内存分区描述块数组OSMemTblOSMemInit就是用来初始化两个数据结构的,详细的过程看下面的函数描述。

 

uCos提供了四个函数:

void  OS_MemInit (void)

         将内存分区描述块数组OSMemTbl中每一项都初始化一下,并且链接起来,链表头当然就是OSMemFreeList了。

        

OS_MEM  *OSMemCreate (void *addr, INT32U nblks, INT32U blksize, INT8U *err)

         对于一块指定地址的内存空间,大小nblks*blksize,将其初始化为nblksblksize大小的块,并且用链表形式链接起来,最后获取一个空闲的内存描述块,用它描述这个内存分区,返回这个内存分区描述块指针。

 

void  *OSMemGet (OS_MEM *pmem, INT8U *err)

         对于指定内存分区,从中获取一块空闲的内存,当然这个块的大小早已定死了。

INT8U  OSMemPut (OS_MEM  *pmem, void *pblk)

         对于指定内存分区,把一个块释放到其中。

 

现在回头看区别uCosLinux0.11的内存分配和管理,可以看出类似和不同的地方,类似的地方在于数据结构的设计以及存储桶的概念应用,不同的地方有好几个,第一,就是Linux0.11有一个存储桶目录列表,各种大小事先固定好,虽然uCos有一个内存分区描述块数组,但是每个内存分区中内存块大小是创建的时候才指定的;第二,uCosLinux0.11相比少了一个层级,Linux0.11看起来是三级结构,uCos只有两级,没有像Linux0.11那样的同种块大小的描述符还存在一个链表链接着,显然Linux0.11的实现更具有动态性,当已无空闲块的时候,系统会再申请一页内存重建一个描述符和存储桶,分配给用户,这和Linux0.11的虚拟内存管理有关。嵌入式OS则不一样,用户必须很清楚内存的情况,然后合理的使用内存。

 

最后再看下VxWorks的实现方式,VxWorks属于嵌入式OS,所以和uCos一样采用了内存分区的概念,用户可以用一段指定的内存创建一个内存分区,然后通过内存分配和释放函数从这个分区中获取和释放内存,只是,VxWorks不同的是,对于内存分区中不划分固定大小的块,创建内存分区刚开始时只有一个空闲块,大小为整个内存分区,之后分配内存是根据指定大小分配内存,这就涉及到教材上常讲的搜索和分配算法,就是找一个合适的块,将其一分为二,一块正好(一般底块)返回给用户,剩下的另一块则链入到空闲块中,每个块都有一个对应的块头来实现链接和描述这个块,所以块头很重要,释放块时会优先考虑和前一块合并,不成则链入空闲块中。VxWorks的数据结构以及代码就不具体描述和贴出来了,原理教材中也都讲过,这里不多赘述,经典的东西太多被提及。

 

         搜索合适块采取的策略很重要,直接影响到系统性能,常被提及的内存碎片问题就是查找算法要考虑的一个大问题,VxWorks5.4的查找策略是最先适合法。

         这里我想强调一下VxWorks6.6对于空闲块管理不是像5.4那样使用链表,而是使用平衡树。

        

         好了,结束了。

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值