内存管理 三

假设系统的可利用内存空间容量为2m个字(地址从0到2m-1),则在开始运行时,整个内存区是一个大小为2m的空闲块,在运行了一段时间之后,被分隔成若干占用块和空闲块。为了在分配时查找方便起见,我们将所有大小相同的空闲块建于一张子表中。每个子表是一个双重链表,这样的链表可能有m+1个,将这m+1个表头指针用向量结构组织成一个表,这就是伙伴系统中的可利用空间表,如图所示:



分配算法: 

       当用户提出大小为n的内存请求时,首先在可利用表上寻找结点大小与n相匹配的子表,若此子表非空,则将子表中任意一个结点分配之即可;若此子表为空,则需从结点更大的非空子表中去查找,直至找到一个空闲块,则将其中一部分分配给用户,而将剩余部分插入相应的子表中。
       若2k-1 < n ≤ 2k-1,又第k+1个子表不空,则只要删除此链表中第一个结点并分配给用户即可;若 2k-2 < n ≤ 2k-1-1,此时由于结点大小为2k-1 的子表为空,则需从结点大小为2k 的子表中取出一块,将其中一半分配给用户,剩余的一半作为一个新结点插入在结点大小为2k-1的子表中,若2k-i-1 < n ≤ 2k-i-1(i为小于是的整数),并且所有结点小于2k的子表均为空,则同样需从结点大小为2k的子表中取出一块,将其中2k-i的一小部分分配给用户,剩余部分分割成若干个结点分别插入在结点大小为2k-1 、 2k-2 、…、 2k-i的子表中。

回收算法:

        在用户释放不再使用的占用块时,系统需将这新的空闲块插入到可利用空间表中去。这里,同样有一个地址相邻的空闲块归并成大块的问题。但是在伙伴系统中仅考虑互为“伙伴”的两个空闲块的归并。
        何谓“伙伴”?如前所述,在分配时经常需要将一个大的空闲块分裂成两个大小相等的存储区,这两个由同一大块分裂出来的小块就称之“互为伙伴”。例如:假设p为大小为pow(2,k)的空闲块的初始地址,且p MOD pow(2,k+1)=0,则初始地址为p和p+pow(2,k)的两个空闲块互为伙伴。在伙伴系统中回收空闲块时,只当其伙伴为空闲块时才归并成大块。也就是说,若有两个空闲块,即使大小相同且地址相邻,但不是由同一大块分裂出来的,也不归并在一起。
        由此,在回收空闲块时,应首先判别其伙伴是否为空闲块,若否,则只要将释放的空闲块简单插入在相应子表中即可;若是,则需在相应子表中找到其伙伴并删除之,然后再判别合并后的空闲块的伙伴是否是空闲块。依此重复,直到归并所得空闲块的伙伴不是空闲块时,再插入到相应的子表中去。


代码如下(只用了单链表):


[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <time.h>  
  4.   
  5. #define MIN_MOMORY_SIZE 536870912   //随机产生的最小内存空间:512M (最大为1G)   
  6. #define INDEX_SIZE 30               //哈希索引表大小   
  7. #define WORKTIME 1500               //系统工作时间   
  8. #define MAX_REQ_SIZE 268435456      //申请空闲内存分配的最大容量:256M   
  9. #define MIN_DUE 30                  //使用内存块的最短时间  
  10. #define MAX_DUE 90                  //使用内存块的最长时间  
  11. #define OCCUPY_INTERVAL 60          //每次分配的最大间隔   
  12. #define USED 1                      //内存块被使用   
  13. #define UNUSED 0                    //内存块未被使用  
  14.   
  15. //内存块链表结点结构   
  16. typedef struct buddy_node {  
  17.     int flag;                       //标记空间是否被使用  
  18.     int base;                       //本块儿内存的基地址   
  19.     int occupy;                     //实际使用空间大小   
  20.     int fragment;                   //碎片大小   
  21.     int duetime;                    //使用时间  
  22.     struct buddy_node *nextPtr;     //指向下一个结点   
  23. } Buddy, *BuddyPtr;  
  24.   
  25. //哈希索引表结构   
  26. typedef struct hash_table {  
  27.     int nodesize;  
  28.     BuddyPtr headPtr;  
  29. } IndexTable;  
  30.   
  31. IndexTable table[INDEX_SIZE];//使用哈希表管理伙伴系统   
  32. int ready = 0;               //需要分配内存的时刻   
  33. int availSpace;              //可分配空间大小   
  34. int totalFragment = 0;       //总碎片大小   
  35.   
  36. //函数:根据k的值计算哈希表项链接的内存块的大小  
  37. int get_size (int k)  
  38. {  
  39.     int i, nodesize = 1;  
  40.       
  41.     for (i = 0; i < k; i ++)  
  42.         nodesize *= 2;  
  43.   
  44.     return nodesize;  
  45. }  
  46.   
  47. //函数:初始化哈希索引表   
  48. void ini_index (void)  
  49. {  
  50.     int i;  
  51.       
  52.     for (i = 0; i < INDEX_SIZE; i ++) {  
  53.         table[i].nodesize = get_size(i);  
  54.         table[i].headPtr = NULL;  
  55.     }   
  56. }  
  57.   
  58. //函数:初始化伙伴系统  
  59. void int_system (int memory_size)  
  60. {  
  61.     int i, addr = 0;  
  62.     int left = memory_size;  
  63.     BuddyPtr newnodePtr = NULL;  
  64.        
  65.     //初始化可分配空间大小和碎片大小   
  66.     availSpace = memory_size;   
  67.     totalFragment = 0;  
  68.       
  69.     //将内存分割成尽量大的2倍数的空闲块并插入到相应的索引表项中  
  70.     for (i = INDEX_SIZE-1; left > 0; i --) {  
  71.         if (left / table[i].nodesize == 1) {  
  72.             newnodePtr = (BuddyPtr) malloc (sizeof (Buddy));//分配结点   
  73.             newnodePtr->flag = UNUSED;  
  74.             newnodePtr->base = addr;  
  75.             newnodePtr->occupy = 0;   
  76.             newnodePtr->fragment = 0;  
  77.             newnodePtr->duetime = 0;  
  78.             newnodePtr->nextPtr = NULL;  
  79.             table[i].headPtr = newnodePtr;  
  80.             addr += table[i].nodesize;  
  81.             left -= table[i].nodesize;  
  82.         }  
  83.     }   
  84. }  
  85.   
  86. //函数:程序运行结束后释放所有结点  
  87. void free_system (void)  
  88. {  
  89.     int i;  
  90.     BuddyPtr tempPtr = NULL, tofreePtr = NULL;  
  91.        
  92.     for (i = 0; i < INDEX_SIZE; i ++) {  
  93.         if (table[i].headPtr) {  
  94.             tempPtr = table[i].headPtr;  
  95.             table[i].headPtr = NULL;  
  96.             //依次释放所有结点  
  97.             while (tempPtr) {  
  98.                 tofreePtr = tempPtr;  
  99.                 tempPtr = tempPtr->nextPtr;  
  100.                 free (tofreePtr);  
  101.             }  
  102.         }  
  103.     }  
  104. }  
  105.   
  106. //函数:添加结点(形参为内存块结点的信息)   
  107. void insert_node (int i, int inbase, int f, int occ, int frag, int d)  
  108. {  
  109.     BuddyPtr newnodePtr = NULL, prePtr = NULL, curPtr = NULL;  
  110.       
  111.     newnodePtr = (BuddyPtr) malloc (sizeof (Buddy));//分配结点  
  112.     newnodePtr->base = inbase;  
  113.     newnodePtr->flag = f;  
  114.     newnodePtr->occupy = occ;   
  115.     newnodePtr->fragment = frag;  
  116.     newnodePtr->duetime = d;  
  117.     newnodePtr->nextPtr = NULL;   
  118.     if (table[i].headPtr == NULL)  
  119.         table[i].headPtr = newnodePtr;  
  120.     else {  
  121.         curPtr = table[i].headPtr;  
  122.         prePtr = NULL;  
  123.         //按地址顺序插入内存块   
  124.         while (curPtr && curPtr->base < inbase) {  
  125.             prePtr = curPtr;  
  126.             curPtr = curPtr->nextPtr;    
  127.         }  
  128.         if (prePtr == NULL) {          //插在最前   
  129.             newnodePtr->nextPtr = curPtr;  
  130.             table[i].headPtr = newnodePtr;  
  131.         }  
  132.         else if (curPtr == NULL) {     //插在最后   
  133.             prePtr->nextPtr = newnodePtr;  
  134.         }  
  135.         else {                         //插在中间   
  136.             prePtr->nextPtr = newnodePtr;  
  137.             newnodePtr->nextPtr = curPtr;  
  138.         }   
  139.     }  
  140. }  
  141.   
  142. //函数:删除结点  
  143. int delete_node (int i, BuddyPtr delPtr)  
  144. {  
  145.     BuddyPtr prePtr = NULL, curPtr = NULL;  
  146.     int basehold = delPtr->base;  
  147.       
  148.     curPtr = table[i].headPtr;  
  149.     while (curPtr != delPtr) {  //寻找要删除的结点的位置   
  150.         prePtr = curPtr;  
  151.         curPtr = curPtr->nextPtr;    
  152.     }  
  153.     if (prePtr == NULL)         //要删除的结点在最前   
  154.         table[i].headPtr = curPtr->nextPtr;  
  155.     else                        //要删除的结点不在链表的最前   
  156.         prePtr->nextPtr = curPtr->nextPtr;  
  157.   
  158.     free (curPtr);              //释放结点   
  159.       
  160.     return basehold;            //返回删除的内存块结点的基地址   
  161. }   
  162.   
  163. //函数:伙伴系统的分配算法   
  164. void buddy_allocate (int time_slice)  
  165. {  
  166.     int i, j, size, due;  
  167.     int state = 0;              //分配状态:0为未分配,1为已分配   
  168.     int inbase, basehold;  
  169.     BuddyPtr curPtr = NULL;  
  170.       
  171.     if (ready == time_slice) {  //到达分配内存的时刻   
  172.         printf ("Time %d:", time_slice);  
  173.         size = 1 + rand () % MAX_REQ_SIZE;            //申请使用内存的大小   
  174.         due = MIN_DUE + rand ()%(MAX_DUE - MIN_DUE);  //申请使用内存的时间  
  175.           
  176.         if (availSpace > size) {//在可分配空间大于申请空间时分配  
  177.             //依次寻找可分配的内存块   
  178.             for (i = 0; (i < INDEX_SIZE) && (state == 0); i ++) {  
  179.                 //找到一个不小于申请大小的块索引  
  180.                 if (table[i].nodesize >= size && table[i].headPtr) {  
  181.                     curPtr = table[i].headPtr;  
  182.                     //遍历相应的循环链表中   
  183.                     while (curPtr && (state == 0)) {  
  184.                         //找到空闲块  
  185.                         if (curPtr->flag == UNUSED) {  
  186.                             //空闲块的大小小于申请大小的2倍,分配   
  187.                             if (table[i].nodesize / size == 1) {  
  188.                                 //在分配的内存块上设置信息   
  189.                                 curPtr->flag = USED;  
  190.                                 curPtr->occupy = size;  
  191.                                 curPtr->fragment = table[i].nodesize - size;  
  192.                                 curPtr->duetime = due + ready;  
  193.                                 //修改可系统分配空间和碎片大小   
  194.                                 availSpace -= table[i].nodesize;  
  195.                                 totalFragment += curPtr->fragment;  
  196.                                 state = 1;//标记已分配   
  197.                                 break;  
  198.                             }  
  199.                             //空闲块的大小刚大于申请大小的2倍  
  200.                             else {  
  201.                                 basehold = delete_node (i, curPtr);//删除较大的空闲块并保留其基地址   
  202.                                 inbase = basehold + table[i].nodesize;  
  203.                                 j = i;  
  204.                                 //分割空闲块   
  205.                                 do {  
  206.                                     j --;  
  207.                                     inbase -= table[j].nodesize;   //设置要添加内存块结点的基地址   
  208.                                     insert_node (j, inbase, UNUSED, 0, 0, 0);//添加较小的空闲块   
  209.                                     printf ("A block cut takes place\n");  
  210.                                 } while (table[j].nodesize / size > 1);  
  211.                                 //分配   
  212.                                 insert_node (j, basehold, USED, size, table[j].nodesize - size, due + ready);  
  213.                                 //修改可系统分配空间和碎片大小   
  214.                                 availSpace -= table[j].nodesize;  
  215.                                 totalFragment += table[j].nodesize - size;  
  216.                                 state = 1;//标记已分配   
  217.                             }  
  218.                         }  
  219.                         //块被占用,查看下一结点   
  220.                         else  
  221.                             curPtr = curPtr->nextPtr;  
  222.                     }  
  223.                 }              
  224.             }  
  225.             printf ("Allocated %d,Fragment %d,Due %d\n", size, totalFragment, ready+due);  
  226.         }  
  227.               
  228.         else if ((availSpace < size) && ((availSpace + totalFragment) >= size))  
  229.             printf ("Allocation failed because of fragment!\n");  
  230.         else  
  231.             printf ("Allocation failed because of no enough unused space!\n");  
  232.               
  233.         ready += (1 + rand() % OCCUPY_INTERVAL);  //下次需要分配内存的时刻  
  234.     }  
  235. }  
  236.   
  237. //函数:伙伴系统的回收算法  
  238. void buddy_retrieve (int time_slice)  
  239. {  
  240.     int i, basehold, dif;  
  241.     int f = 0;  
  242.     int Modnext=0;  
  243.     BuddyPtr curPtr = NULL, todelPtr = NULL;   
  244.       
  245.     //依次查找,并回收需要回收的块   
  246.     for (i = 0; i < INDEX_SIZE; i ++) {  
  247.         if (table[i].headPtr) {  
  248.             curPtr = table[i].headPtr;  
  249.             while (curPtr) {  
  250.                 if ((curPtr->flag == USED) && (curPtr->duetime == time_slice)) {//需要回收   
  251.                     //修改可系统分配空间和碎片大小   
  252.                     availSpace += table[i].nodesize;  
  253.                     totalFragment -= curPtr->fragment;  
  254.                     //回收为空闲块   
  255.                     curPtr->flag = UNUSED;  
  256.                     curPtr->occupy = 0;   
  257.                     curPtr->fragment = 0;  
  258.                     curPtr->duetime = 0;  
  259.                     printf ("Time %d:Retrieve %d,Fragment %d\n", time_slice, table[i].nodesize, totalFragment);  
  260.                 }  
  261.                 curPtr = curPtr->nextPtr;  
  262.             }  
  263.         }  
  264.     }  
  265.       
  266.     //合并空闲块  
  267.     for (i = 0; i < INDEX_SIZE; i ++) {  
  268.         if (table[i].headPtr) {              
  269.             curPtr = table[i].headPtr;  
  270.             while (curPtr && curPtr->nextPtr) {  
  271.                 //将地址连续且都为空闲的块合并后加入下一级的链表中   
  272.                 if (curPtr->flag == UNUSED && (curPtr->nextPtr)->flag == UNUSED) {  
  273.                     dif = (curPtr->nextPtr)->base - curPtr->base;  
  274.                     Modnext = ((int)(curPtr->nextPtr->base))%(2*table[i].nodesize);  
  275.                     if ((dif == table[i].nodesize)&&(Modnext==0)) {  
  276.                         //删除两个结点   
  277.                         todelPtr = curPtr;  
  278.                         curPtr = curPtr->nextPtr;  
  279.                         basehold = delete_node (i, todelPtr);  
  280.                         todelPtr = curPtr;  
  281.                         curPtr = curPtr->nextPtr;  
  282.                         delete_node (i, todelPtr);  
  283.                         insert_node (i+1, basehold, UNUSED, 0, 0, 0);//添加合并后的结点   
  284.                         printf ("Two blocks merge\n");  
  285.                     }  
  286.                     else  
  287.                         curPtr = curPtr->nextPtr;  
  288.                 }  
  289.                 else  
  290.                     curPtr = curPtr->nextPtr;  
  291.             }  
  292.         }  
  293.     }  
  294. }  
  295.   
  296. //函数:伙伴系统的处理过程   
  297. void buddy_system (void)  
  298. {  
  299.     int time_slice = 0;  
  300.       
  301.     //在每个时间片内使用分配算法和回收算法   
  302.     for (; time_slice < WORKTIME; time_slice ++) {  
  303.         buddy_allocate (time_slice);         //分配算法   
  304.         buddy_retrieve (time_slice);         //回收算法   
  305.     }  
  306. }  
  307.   
  308.   
  309. int main(int argc, char *argv[])  
  310. {  
  311.     int memory_size;  
  312.       
  313.     ini_index ();               //初始化哈希索引表   
  314.     srand (time (NULL));        //设置随机数种子  
  315.     //随机产生需要管理的内存大小:512M ~ 1G   
  316.     memory_size = MIN_MOMORY_SIZE + rand() % MIN_MOMORY_SIZE;   
  317.     printf ("The size of memory is:%d\n", memory_size);  
  318.       
  319.     int_system (memory_size);   //初始化伙伴系统   
  320.       
  321.     buddy_system ();            //伙伴系统的处理过程  
  322.     printf ("Time %d:System execution stops and the spaces are all freed.\n", WORKTIME);  
  323.       
  324.     free_system ();             //释放所有结点   
  325.       
  326.     return 0;  
  327. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值