动态内存分区分配方式模拟[转帖]

百度面试题:

给定一块内存,大小为1M,现有一些内存请求序列1K、2K、4K、10K........

要求模拟实现new/delete内存分配过程。


对应题目如下:

 假设初始态下,可用内存空间为640K,并有下列请求序列,请分别用首次适应算法和最佳适应算法

为作业分配和回收内存块,并显示出每次分配和回收后的空闲分区链的情况来以及内存占用情况图。

作业1申请130K

作业2申请60K
作业3申请100k
作业2释放60K
  ......


一、算法的基本思想


根据题目要求,使用首次适应算法最佳适应算法分别实现内存的动态分区,因此说明一下这两种算法的基本思想:


首先,维护一个空闲分区链表,初始时链表只有一个节点就是整个内存块,在一系列的内存分配与释放之后,分区链表呈现一种空闲与占用交替的状态,一下讨论的时候,针对的就是分区链表普遍的状态的时候。链表结构如下:

struct SubAreaNode
{
    int address;    //分区起始地址
    int size;       //分区大小
    int state;      //分区状态(0,1)两个标记
    int taskNo;     //记录作业号
    SubAreaNode *prior; //分区的前向指针  前驱
    SubAreaNode *nexr;  //分区的后继指针
}

使用最佳匹配的时候还要开辟一个负责的指针数组,负责存储空闲节点,针对空闲节点指针所指向的节点的 size 大小进行排序。

说明:分区状态 1 表示占用,0表示空闲。


算法思想如下:


(1)为任务分配内存空间的思想


1、首次适应算法中,空闲分区链是按地址递增的次序链接的,当要分配内存空间时,就在所有空闲分区中查找满足大小要求的可用块,只要找到第一个足以满足要求的空间就停止查找,并把它分配给请求者,如果该空闲空间与所需空间大小一样,维护一个分区状态标志量,将该分区的状态改为1,表明已被分配,若还有剩余,则将剩余空间重新划为一个空闲分区,有新的起始地址,状态为0。如果从头到尾找不到,则分配失败。

2、最佳适应算法的空闲链是按照空闲块的大小为序、所有空闲区按容量从小到大的顺序形成空闲分区链。在进行内存分配时候,它在满足需要的前提下,尽量分配最小的空闲块,这样每次查找分配时,从链首开始查找,第一次找到的能满足要求的必然的最佳的,若空闲空间大小与要分配的大小相同时,可直接将其状态改为1即可,若有剩余,则将剩余空闲空间重新划分为一个空闲区,然后根据空闲区的大小对链表进行重新排序,这里对空闲分区大小排序采用了快速排序算法。


(2) 已经执行完的任务释放内存空间思想


首次适应算法的分区回收过程相对简单,因为分区链是按照地址顺序链接的,因此释放内存时只需要判断要释放的分区前后是否也为空闲区,如果前后有空闲分区,则需要进行合并,合并的原则是排在后面的分区合并到前面的分区中,如果前后分区都已分配,则直接将该分区状态改为0即可。

最佳适应算法分区回收时,因为它的空闲分区链是按照空间大小排列的,因此不仅要看要释放分区前后是否为空闲,还要判断其地址是否前后相接,若地址不相接,则即使要释放分区前后均为空闲区,也不能进行合并,而且每次释放后要根据释放空间的大小对链表进行重新排序,同样采用快速排序算法进行重新排序。


二、通用算法分配内存
   通用算法分配内存主要是实现对内存分配,因为最佳算法与首次算法对内存的分配唯一区别是最佳算法分配完内存后,需要重新排序。因此可以把这两者共同地方统一设计。
通用算法分配内存原理是首先判断申请内存的大小能否在空闲分区中找到适合的,如果找到分两种情况,一是刚好大小一致,二是空闲分区比申请内存大小大,则需要划分空闲分区,剩余的空间为新的分区。

三、首次算法回收内存
   首次算法回收内存主要是实现对内存回收,关键点是根据分区前后指针判断回收分区的前后是否有空闲。如果有需要进行合并。注意在合并时候,删除不用的节点后,需要重新定义新合并分区的新下一分区前驱指针:pNext->next->prior = pfirstFree->prior。


四、最佳算法回收内存
最佳算法回收内存主要是实现对内存回收,关键点是根据地址判断前后分区有否空闲,如果有需要合并。在回收后,需要重新排序空闲分区。


五、空闲分区的重新排序
  空闲分区的重新排序,需要定义一个空闲分区指针数组,一个空闲分区的空间大小数组,然后调用快速排序函数,根据空间大小进行排序,排序完成后,空闲分区指针数组相应也进行了重新排序,接着是根据指针数组对原来的空闲分区链表排序。


六、快速排序
  快速排序是在待排序n个记录中任取一个作为“基准”,将其余记录分为两组,第一组中各记录的值均小于或等于基准的值,第二组中各记录的值均大于或等于基准的值。对所分成两组分别重复上述方法,直到所有记录排在合适位置上。
Parr[]是空闲分区链表指针数组,arr[]是记录每个分区空间大小的整形数组。所以使用快速算法对每个分区空间大小排序,排序的同时也相应调整空闲分区链表指针的先后顺序,这样在排序后,可以利用Parr[]对原来的分区链表进行重新定义。


七、执行截图:


附注:完整程序代码查看地址:
http://blog.csdn.net/raymentblog/article/details/6173073

转自:http://blog.sina.com.cn/s/blog_4deeda250100pf4z.html

同时参考:http://hi.baidu.com/avatar_lei/item/58b2ab11f1ed2d4e3b176efb

你可能感兴趣的:(算法,struct,面试,百度,作业)