- 李微微
- 201821121001
- 计算1811
1. 记录内存空间使用情况
①根据实验课上的PPT,记录进程使用了哪些内存空间,用链表实现。在结构体里声明进程ID、占用大小、起始地址、进程名和指向自己类型的指针,用于存放进程信息。
/*记录内存空间使用情况*/ typedef struct allocated_block{ int pid; int size; int start_addr; char process_name[PNAME_LEN]; struct allocated_block *next; }AB;
②定义一个全局指针变量,作为进程分配内存块的首指针,指向链表头结点。在分配内存时,用指针将该结点加入链表;在释放内存时,用指针将该结点从链表中删除。
AB *allocated_block_head = NULL;
2. 记录空闲分区
①同样用链表记录空闲分区,同样定义一个结构体,声明占用大小、起始地址和指向自己类型的指针。
typedef struct free_block_type{ int size; int start_addr; struct free_block_type *next; }FBT;
②同样定义一个全局指针变量,作为内存中空闲块链表首指针,指向链表头结点。在刚初始化内存空间时,内存空间都是空闲分区;当分配内存空间后,内存管理算法会从空闲分区分出一块,这样就会导致空闲分区不连续。所以将空闲分区结点插入,并重新排序。释放内存时,分区结点从链表中删除。
FBT *free_block; //指向内存中空闲块链表的首指针
3. 内存分配算法
- 使用的内存分配:首次适配
- 代码包括分配内存算法、应用分配内存算法的模块(包括内存紧缩后分配函数、重排空闲分区函数)、为进程分配内存模块。
- 算法的本质是,把最合适的空闲区分配给进程。空闲区足够大则分割,分割后会打乱空闲区,就需要把空闲区加入链表,重新排序;空闲区不够则用内存紧缩,合并空闲分区,再分配。
void Do_Allocate_Mem(AB *ab){ //分配内存 int request = ab->size; FBT *tmp = free_block; while(tmp != NULL){ if(tmp->size >= request){ ab->start_addr = tmp->start_addr; int residue = tmp->size - request; tmp->size = residue; tmp->start_addr = tmp->start_addr + request; return ; } tmp = tmp->next; } } int Allocate_Mem(AB *ab){ //分配内存应用 FBT *fbt,*pre; int request_size=ab->size; fbt = pre = free_block; int f = Find_Free_Mem(request_size); //寻找可分配 if(f == -1){ //空闲内存不足 printf("Not enough free memory!\n"); return -1; }else{ if(f == 0){ //内存紧缩后分配 Memory_Compact(); } Do_Allocate_Mem(ab); //分配 } Rearrange(ma_algorithm); //重排空闲分区 return 1; } int Alloc_Process(PRO prc){ //为进程分配内存 AB *ab; int ret; ab = (AB*)malloc(sizeof(AB)); if(!ab) exit(-5); ab->next=NULL; pid++; strcpy(ab->process_name,prc.process_name); ab->pid = pid; ab->size=prc.size+rand()%ALLOC_SIZE; //随机分配内存 ret = Allocate_Mem(ab); //分配内存,ret==1表示分配成功 if((ret == 1) && (allocated_block_head == NULL)){ //若allocated_block_head尚未赋值 allocated_block_head = ab; return 1; }else if(ret == 1){ //分配成功 ab->next = allocated_block_head; allocated_block_head = ab; return 2; }else if(ret == -1){ //分配不成功 printf("Fail!\n"); free(ab); return -1; } return 3; }
void Memory_Compact(){ //进行内存紧缩 FBT *fbttmp = free_block; AB *abtmp = allocated_block_head; int sum = 0; while(fbttmp!=NULL){ //检测剩余内存 sum += fbttmp->size; fbttmp = fbttmp->next; } fbttmp = free_block; //合并区块 fbttmp->size = sum; fbttmp->start_addr = 0; fbttmp->next=NULL; FBT *pr = free_block->next; //释放分区 while(pr != NULL){ fbttmp = pr->next; free(pr); pr = fbttmp; } Sort_AB(); //已分配空间重新排序 Reset_AB(sum); }
4. 内存释放算法
- 内存释放包括链表结点释放、更新分区表、释放进程内存(寻找链表结点函数)。
- 算法过程是释放结点,再将释放的结点插入空闲分区末尾,再排序,合并必要的空闲分区,最后按首次适配算法排序。
- 代码
int Dispose(AB *free_ab){ //释放链表ab节点 AB *pre,*ab; if(free_ab == allocated_block_head){ //若释放首节点 allocated_block_head = allocated_block_head->next; free(free_ab); return 1; } pre = allocated_block_head; //否则 ab = allocated_block_head->next; while(ab!=free_ab){ pre = ab; ab = ab->next; } pre->next = ab->next; free(ab); return 2; } int Free_Mem(AB *ab){ //更新分区表归还已分配区,以及可能的合并 int algorithm = ma_algorithm; FBT *fbt,*pre,*work; fbt = (FBT*)malloc(sizeof(FBT)); if(!fbt) return -1; fbt->size = ab->size; fbt->start_addr = ab->start_addr; //插入链尾 work = free_block; if(work == NULL){ free_block = fbt; fbt->next == NULL; }else{ while(work ->next != NULL){ work = work->next; } fbt->next = work->next; work->next = fbt; } Rearrange_FIR(); //首次适配算法 pre = free_block; while(pre->next){ work = pre->next; if(pre->start_addr + pre->size == work->start_addr ){ pre->size = pre->size + work->size; pre->next = work->next; free(work); continue; }else{ pre = pre->next; } } Rearrange(ma_algorithm); //按照当前算法排序 return 1; } int Kill_Process(int pid){ //释放进程内存 AB *ab; ab = Find_Process(pid); if(ab!=NULL){ Free_Mem(ab); //释放分配表 Dispose(ab); //释放节点 return 0; }else{ return -1; } }
5. 运行结果
(1)产生测试数据
随机为3个进程分配、释放内存10次以上,即随机产生10组以上数据:
#define PROCESS_NUM 3 //进程数
int main(int argc, char const *argv[]){ int sel1,sel2; int total=0; //记录分配内存的次数 free_block=Init_Free_Block(mem_size); //初始化空闲区 PRO prc[PROCESS_NUM]; //存放要加载的进程 Init_Program(prc,PROCESS_NUM); //对这几个程进程进行初始化 srand((unsigned)time(NULL)); for(int i=0;i<DATA_NUM;++i) { sel1=rand()%2; int count=0; //统计三个进程中有多少个进程已经分配内存 for(int j=0;j<PROCESS_NUM;++j){ if(prc[j].pid!=-1) count++; } //如果全部分配进程或者进程分配到达10次,那么就不能继续分配内存 if((count==PROCESS_NUM && sel1==0)||total==10) sel1=1; //如果全部未分配进程,那么就不能继续释放内存 324 if(count==0 && sel1==1) sel1=0; if(sel1==0) //为进程分配内存 { //随机找到一个未分配内存的进程 do{ sel2=rand()%PROCESS_NUM; }while(prc[sel2].pid!=-1); Alloc_Process(prc[sel2]); //分配内存空间 prc[sel2].pid=pid; //改变标记 total++; Display_Mem_Usage(); //显示结果 } else //释放进程占用的内存空间 { do{ //随机找到一个可释放进程 sel2=rand()%PROCESS_NUM; }while(prc[sel2].pid==-1); Kill_Process(prc[sel2].pid);//释放内存空间 prc[sel2].pid=-1; //改变标记 Display_Mem_Usage(); //显示 } } }
(2)解释结果
运行结果:
解释:
①第一次内存分配:进程名为process-03,起始地址为0,进程占用内存大小为98;剩余空闲分区首地址为98,大小为926。
分配结果:
释放进程process-03:
②第二次内存分配:进程名为process-02,起始地址为0,进程占用内存大小为107;剩余空闲分区首地址为107,大小为917。
分配结果:
释放进程process-02:
③第三次内存分配:进程名为process-03,起始地址为0,进程占用内存大小为107;剩余空闲分区首地址为107,大小为917。未释放进程。
分配结果:
④第四次内存分配:进程名为process-01,起始地址为96,进程占用内存大小为67;剩余空闲分区首地址为163,大小为861。未释放进程。
6. 源码
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #include<time.h> 5 6 #define PNAME_LEN 32 //进程名 7 #define MEM_SIZE 1024 //内存大小 8 #define MEM_START 0 //起始位置 9 #define MATE_FIR 1 //定义首次适配算法 10 #define DATA_NUM 20 //定义产生数据的组数 11 #define PROCESS_NUM 3 //进程数 12 #define PROCESS_SIZE 10 //进程大小 13 #define ALLOC_SIZE 100 //随机分配最大值 14 15 /*记录内存空间使用情况,每个进程分配到的内存块描述*/ 16 typedef struct allocated_block{ 17 int pid; 18 int size; 19 int start_addr; 20 char process_name[PNAME_LEN]; 21 struct allocated_block *next; 22 }AB; 23 /*记录空闲分区,描述每一个空闲块的数据结构*/ 24 typedef struct free_block_type{ 25 int size; 26 int start_addr; 27 struct free_block_type *next; 28 }FBT; 29 /*描述每个进程结构*/ 30 typedef struct Process{ 31 int size; 32 int pid; 33 char process_name[PNAME_LEN]; 34 }PRO; 35 36 FBT *free_block;//指向内存中空闲块链表的首指针 37 /*进程分配内存块链表的首指针*/ 38 AB *allocated_block_head = NULL; 39 40 static int pid = 0; /*初始pid*/ 41 42 int mem_size = MEM_SIZE; //内存大小 43 int ma_algorithm = MATE_FIR; //当前分配算法为首次适配算法 44 int min_mem_size = 0; //设置剩余分区过小的标志 45 46 //初始化空闲分区链表 47 FBT *Init_Free_Block(int mem_size){ 48 FBT *fb; 49 fb = (FBT*)malloc(sizeof(FBT)); 50 if(fb==NULL){ 51 printf("No mem\n"); 52 return NULL; 53 } 54 fb->size = mem_size; 55 fb->start_addr = MEM_START; 56 fb->next = NULL; 57 return fb; 58 } 59 60 void Rearrange_FIR(){ //首次适配算法,冒泡起始地址升序 61 if(free_block == NULL || free_block->next == NULL) 62 return; 63 FBT *t1,*t2,*head; 64 head = free_block; 65 for(t1 = head->next;t1;t1 = t1->next){ 66 for(t2 = head;t2 != t1;t2=t2->next){ 67 if(t2->start_addr > t2->next->start_addr){ 68 int tmp = t2->start_addr; 69 t2->start_addr = t2->next->start_addr; 70 t2->next->start_addr = tmp; 71 tmp = t2->size; 72 t2->size = t2->next->size; 73 t2->next->size = tmp; 74 } 75 } 76 } 77 } 78 void Rearrange(int algorithm){ //按指定的算法整理内存空闲块链 79 Rearrange_FIR(); 80 } 81 82 int Display_Mem_Usage(){ //显示当前内存的使用情况 83 FBT *fbt = free_block; 84 AB *ab = allocated_block_head; 85 printf("------------------------------------------------------------------\n"); 86 printf("Free Memory:\n"); //空闲内存 87 printf("%20s %20s\n"," start_addr"," size"); 88 while(fbt!=NULL){ 89 if(fbt->size!=0) 90 printf("%20d %20d\n",fbt->start_addr,fbt->size); 91 fbt = fbt->next; 92 } 93 printf("\n"); 94 printf("Used Memory:\n"); //已分配内存 95 printf("%10s %20s %20s %10s\n","PID","ProcessName","start_addr","size"); 96 while(ab != NULL){ 97 printf("%10d %20s %20d %10d\n",ab->pid,ab->process_name,ab->start_addr,ab->size); 98 ab = ab->next; 99 } 100 printf("------------------------------------------------------------------\n"); 101 return 0; 102 } 103 int Dispose(AB *free_ab){ //释放链表ab节点 104 AB *pre,*ab; 105 if(free_ab == allocated_block_head){ //若释放首节点 106 allocated_block_head = allocated_block_head->next; 107 free(free_ab); 108 return 1; 109 } 110 pre = allocated_block_head; //否则 111 ab = allocated_block_head->next; 112 while(ab!=free_ab){ 113 pre = ab; 114 ab = ab->next; 115 } 116 pre->next = ab->next; 117 free(ab); 118 return 2; 119 } 120 int Free_Mem(AB *ab){ //更新分区表归还已分配区,以及可能的合并 121 int algorithm = ma_algorithm; 122 FBT *fbt,*pre,*work; 123 fbt = (FBT*)malloc(sizeof(FBT)); 124 if(!fbt) return -1; 125 126 fbt->size = ab->size; 127 fbt->start_addr = ab->start_addr; //插入链尾 128 work = free_block; 129 if(work == NULL){ 130 free_block = fbt; 131 fbt->next == NULL; 132 }else{ 133 while(work ->next != NULL){ 134 work = work->next; 135 } 136 fbt->next = work->next; 137 work->next = fbt; 138 } 139 Rearrange_FIR(); //首次适配算法 140 pre = free_block; 141 while(pre->next){ 142 work = pre->next; 143 if(pre->start_addr + pre->size == work->start_addr ){ 144 pre->size = pre->size + work->size; 145 pre->next = work->next; 146 free(work); 147 continue; 148 }else{ 149 pre = pre->next; 150 } 151 } 152 Rearrange(ma_algorithm); //按照当前算法排序 153 return 1; 154 } 155 AB *Find_Process(int pid){ //找到pid对应的链表节点 156 AB *tmp = allocated_block_head; 157 while(tmp != NULL){ //如果找不到 158 if(tmp->pid == pid){ 159 return tmp; 160 } 161 tmp = tmp->next; 162 } 163 printf("Process with PID %d not found!\n",pid); 164 return NULL; 165 } 166 int Kill_Process(int pid){ //释放进程内存 167 AB *ab; 168 ab = Find_Process(pid); 169 if(ab!=NULL){ 170 Free_Mem(ab); //释放分配表 171 Dispose(ab); //释放节点 172 return 0; 173 }else{ 174 return -1; 175 } 176 } 177 int Find_Free_Mem(int request){ //寻找非进程分配分区 178 FBT *tmp = free_block; 179 int mem_sum = 0; 180 while(tmp){ 181 if(tmp->size >= request){ //若可以直接分配 182 return 1; 183 } 184 mem_sum += tmp->size; 185 tmp = tmp->next; 186 } 187 if(mem_sum >= request){ //若可以合并后分配 188 return 0; 189 }else{ //若空间不足 190 return -1; 191 } 192 } 193 void Sort_AB(){ //将已分配表按起始地址从大到小排序 194 if(allocated_block_head == NULL || allocated_block_head->next == NULL) 195 return; 196 AB *t1,*t2,*head; 197 head = allocated_block_head; 198 for(t1 = head->next;t1;t1 = t1->next){ 199 for(t2 = head;t2 != t1;t2=t2->next){ 200 if(t2->start_addr > t2->next->start_addr){ 201 int tmp = t2->start_addr; 202 t2->start_addr = t2->next->start_addr; 203 t2->next->start_addr = tmp; 204 tmp = t2->size; 205 t2->size = t2->next->size; 206 t2->next->size = tmp; 207 } 208 } 209 } 210 } 211 void Reset_AB(int start){ //重新分配内存地址 212 AB *tmp = allocated_block_head; 213 while(tmp != NULL){ 214 tmp->start_addr = start; 215 start += tmp->size; 216 tmp = tmp->next; 217 } 218 } 219 void Memory_Compact(){ //进行内存紧缩 220 FBT *fbttmp = free_block; 221 AB *abtmp = allocated_block_head; 222 int sum = 0; 223 while(fbttmp!=NULL){ //检测剩余内存 224 sum += fbttmp->size; 225 fbttmp = fbttmp->next; 226 } 227 fbttmp = free_block; //合并区块 228 fbttmp->size = sum; 229 fbttmp->start_addr = 0; 230 fbttmp->next=NULL; 231 FBT *pr = free_block->next; //释放分区 232 while(pr != NULL){ 233 fbttmp = pr->next; 234 free(pr); 235 pr = fbttmp; 236 } 237 Sort_AB(); //已分配空间重新排序 238 Reset_AB(sum); 239 } 240 void Do_Allocate_Mem(AB *ab){ //分配内存 241 int request = ab->size; 242 FBT *tmp = free_block; 243 while(tmp != NULL){ 244 if(tmp->size >= request){ 245 ab->start_addr = tmp->start_addr; 246 int residue = tmp->size - request; 247 tmp->size = residue; 248 tmp->start_addr = tmp->start_addr + request; 249 return ; 250 } 251 tmp = tmp->next; 252 } 253 } 254 int Allocate_Mem(AB *ab){ //分配内存应用 255 FBT *fbt,*pre; 256 int request_size=ab->size; 257 fbt = pre = free_block; 258 int f = Find_Free_Mem(request_size); //寻找可分配 259 if(f == -1){ //空闲内存不足 260 printf("Not enough free memory!\n"); 261 return -1; 262 }else{ 263 if(f == 0){ //内存紧缩后分配 264 Memory_Compact(); 265 } 266 Do_Allocate_Mem(ab); //分配 267 } 268 Rearrange(ma_algorithm); //重排空闲分区 269 return 1; 270 } 271 int Alloc_Process(PRO prc){ //为进程分配内存 272 AB *ab; 273 int ret; 274 ab = (AB*)malloc(sizeof(AB)); 275 if(!ab) exit(-5); 276 ab->next=NULL; 277 pid++; 278 strcpy(ab->process_name,prc.process_name); 279 ab->pid = pid; 280 ab->size=prc.size+rand()%ALLOC_SIZE; //随机分配内存 281 ret = Allocate_Mem(ab); //分配内存,ret==1表示分配成功 282 if((ret == 1) && (allocated_block_head == NULL)){ //若allocated_block_head尚未赋值 283 allocated_block_head = ab; 284 return 1; 285 }else if(ret == 1){ //分配成功 286 ab->next = allocated_block_head; 287 allocated_block_head = ab; 288 return 2; 289 }else if(ret == -1){ //分配不成功 290 printf("Fail!\n"); 291 free(ab); 292 return -1; 293 } 294 return 3; 295 } 296 297 //初始化进程 298 void Init_Program(PRO prc[],int n) 299 { 300 for(int i=0;i<n;++i){ 301 prc[i].size=PROCESS_SIZE; 302 prc[i].pid=-1; 303 sprintf(prc[i].process_name,"process-%02d",i+1); 304 } 305 } 306 307 int main(int argc, char const *argv[]){ 308 int sel1,sel2; 309 int total=0; //记录分配内存的次数 310 free_block=Init_Free_Block(mem_size); //初始化空闲区 311 PRO prc[PROCESS_NUM]; //存放要加载的进程 312 Init_Program(prc,PROCESS_NUM); //对这几个程进程进行初始化 313 srand((unsigned)time(NULL)); 314 for(int i=0;i<DATA_NUM;++i) 315 { 316 sel1=rand()%2; 317 int count=0; //统计三个进程中有多少个进程已经分配内存 318 for(int j=0;j<PROCESS_NUM;++j){ 319 if(prc[j].pid!=-1) 320 count++; 321 } //如果全部分配进程或者进程分配到达10次,那么就不能继续分配内存 322 if((count==PROCESS_NUM && sel1==0)||total==10) 323 sel1=1; //如果全部未分配进程,那么就不能继续释放内存 324 if(count==0 && sel1==1) 325 sel1=0; 326 if(sel1==0) //为进程分配内存 327 { //随机找到一个未分配内存的进程 328 do{ 329 sel2=rand()%PROCESS_NUM; 330 }while(prc[sel2].pid!=-1); 331 Alloc_Process(prc[sel2]); //分配内存空间 332 prc[sel2].pid=pid; //改变标记 333 total++; 334 Display_Mem_Usage(); //显示结果 335 } 336 else //释放进程占用的内存空间 337 { 338 do{ //随机找到一个可释放进程 339 sel2=rand()%PROCESS_NUM; 340 }while(prc[sel2].pid==-1); 341 Kill_Process(prc[sel2].pid);//释放内存空间 342 prc[sel2].pid=-1; //改变标记 343 Display_Mem_Usage(); //显示 344 } 345 } 346 }