当前位置:   article > 正文

操作系统实验报告②_编写c语言程序,模拟实现首次、最佳、最坏适应三种算法的内存块分配和回收。假

编写c语言程序,模拟实现首次、最佳、最坏适应三种算法的内存块分配和回收。假

编写C语言程序,模拟实现首次/最佳/最坏适应算法(选择其中之一即可)的内存块分配和回收,要求每次分配和回收后显示出空闲分区和已分配分区的情况。假设初始状态下,可用的内存空间为640KB。

假设下列作业请求序列:

(1)作业1 申请130 KB (2)作业2 申请60 KB (3)作业3 申请100 KB

(4)作业2 释放60 KB (5)作业3 释放100 KB (6)作业1 释放130 KB

显示每次作业申请或释放后当前内存情况。

分析设计:

分析设计如下:

(1)程序初始需要提供用户选择方式。选择首次适应算法,还是最佳是适应算法,选择作业的回收,作业的展示,程序的退出能。

(2)当用户选择首次适应算法或者最佳适应算法,需要用户输入分配内存的大小。在输入大小时在根据算法的设计进行分配。

(3)当内存分配过后,如果分配成功就需要提示成功,如果失败则需要提示失败。

(4)内存回收需要用户输入回收作业的ID,根据作业的ID对内存进行回收。在回收时要分多种情况进行判断。

(5)作业展示,需要向用户展示,作业的ID,起始地址,内存大小,状态是已分配还是空闲。

(6)一个作业需要用到数据结构中的双向列表,用一个双向列表来表示节点。

程序代码:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. struct area
  4. {
  5. int id; // 编号
  6. int addr_front; //首地址
  7. int addr_end; //结束地址
  8. int size; //分区大小
  9. int flag; //分配标志,0表示空闲,1表示占用
  10. struct area *front; //上一分区
  11. struct area *next; //下一分区
  12. };
  13. typedef struct area partion;
  14. partion *head = NULL; //分区队列头节点
  15. int need; //需求
  16. int choice = 1; //操作选项
  17. partion *createPartion(int id, int addr_front, int size, int flag); //生成一个节点
  18. void inputNeed(); //输入需求量
  19. void assign(partion *ptr, int need); //分配分区
  20. void first_fit(); //首次适应算法
  21. void best_fit(); //最佳适应算法
  22. void showMemoryInfo(); //打印分区分配状况
  23. void recovery(); //分区回收
  24. void changeIdValue(partion *ptr, int delta); //改变从ptr开始所有节点的id值
  25. int main(void)
  26. {
  27. head = createPartion(0, 0, 640, 0);
  28. while (choice != 0)
  29. {
  30. puts("-------------------\n请选择操作:\n1:首次适应;\n2:最佳适应;\n3:内存回收;\n4:展示详细信息;\n0:推出......\n-------------------");
  31. scanf("%d", &choice);
  32. switch (choice)
  33. {
  34. case 1:
  35. inputNeed();
  36. first_fit();
  37. break;
  38. case 2:
  39. inputNeed();
  40. best_fit();
  41. break;
  42. case 3:
  43. recovery();
  44. showMemoryInfo();
  45. break;
  46. case 4:
  47. showMemoryInfo();
  48. break;
  49. case 0:
  50. puts("byebye");
  51. break;
  52. default:
  53. break;
  54. }
  55. }
  56. return 0;
  57. }
  58. //创建一个节点
  59. partion *createPartion(int id, int addr_front, int size, int flag)
  60. {
  61. partion *p = (partion *)malloc(sizeof(partion));
  62. p->id = id;
  63. p->addr_front = addr_front;
  64. p->addr_end=addr_front+size-1;
  65. p->size = size;
  66. p->flag = flag;
  67. p->front = NULL;
  68. p->next = NULL;
  69. return p;
  70. }
  71. void inputNeed()
  72. {
  73. printf("请输入需要的内存大小:");
  74. scanf("%d", &need);
  75. }
  76. void first_fit()
  77. {
  78. partion *fit = NULL;
  79. partion *ptr = head;
  80. while (ptr != NULL)
  81. {
  82. if (ptr->size >= need && ptr->flag == 0)//如果是空闲并且大小大于则给予分配
  83. {
  84. fit = ptr;
  85. break;
  86. }
  87. ptr = ptr->next;
  88. }
  89. if (fit != NULL)
  90. {
  91. assign(fit, need);
  92. printf("内存分配成功,分配如下:\n");
  93. showMemoryInfo();
  94. }
  95. else
  96. {
  97. puts("抱歉,内存分配失败!");
  98. free(fit);
  99. }
  100. }
  101. void best_fit()
  102. {
  103. partion *fit = NULL;
  104. partion *ptr = head;
  105. int flag = 0; //flag 表示是否找到可分配的分区
  106. while (ptr != NULL)
  107. {
  108. if (ptr->flag == 0 && ptr->size >= need)
  109. {
  110. if (flag == 0)
  111. {
  112. //只有遇到的第一个可分配分区会执行此操作
  113. fit = ptr;
  114. flag = 1;
  115. }
  116. else
  117. {
  118. //若遇到可分配且分区更小即更适合的则更新
  119. if (ptr->size < fit->size)
  120. {
  121. fit = ptr;
  122. }
  123. }
  124. }
  125. ptr = ptr->next;
  126. }
  127. //先处理没找到合适分区的情况
  128. if (flag == 0)
  129. {
  130. puts("抱歉,未找到合适的分区!");
  131. free(fit);
  132. return;
  133. }
  134. //找到则分配
  135. assign(fit, need);
  136. puts("内存分配成功,分配如下:\n!");
  137. showMemoryInfo();
  138. }
  139. void showMemoryInfo()
  140. {
  141. partion *ptr = head;
  142. puts("\n\n---------------------------------------------");
  143. puts("总内存分配情况如下:");
  144. puts("---------------------------------------------");
  145. puts("序号ID****开始地址****结束地址****内存大小****状态****");
  146. while (ptr != NULL)
  147. {
  148. printf("%-12d%-12d%-12d%-12d",ptr->id,ptr->addr_front,ptr->addr_end,ptr->size);
  149. // printf("序号id:%21d%10c\n开始地址:%10d%10c\n", ptr->id, '|', ptr->addr_front, '|');
  150. //printf("结束地址:%10d%10c\n", ptr->addr_end, '|');
  151. //printf("内存大小:%11d%10c\n", ptr->size, '|');
  152. printf("%-12s\n", ptr->flag == 0 ? "空闲" : "已分配");
  153. puts("-----------------------------------------------------");
  154. ptr = ptr->next;
  155. }
  156. puts("---------------------------------------------\n\n");
  157. }
  158. void assign(partion *ptr, int need)
  159. {
  160. if (need == ptr->size)//空闲的空间恰好等同需要的空间
  161. {
  162. ptr->flag = 1;
  163. return;
  164. }
  165. //空闲的空间大于需要的空间
  166. partion *assigned = createPartion(ptr->id, ptr->addr_front, need, 1);
  167. assigned->next = ptr;
  168. assigned->front = ptr->front;
  169. changeIdValue(ptr, 1);//把后面的节点的id值都增加1
  170. ptr->addr_front += need;
  171. ptr->size -= need;
  172. if (ptr->front != NULL)//空闲区的头不空,就在前一个节点后面添加分配的节点
  173. {
  174. ptr->front->next = assigned;
  175. }
  176. else//空闲节点前没有节点
  177. {
  178. head = assigned;
  179. }
  180. ptr->front = assigned;//空闲节点的头指向新分配的
  181. }
  182. void recovery()
  183. {
  184. printf("请输入需要回收作业的ID号:");
  185. int id, flag = 0;
  186. scanf("%d", &id);
  187. partion *ptr = head;
  188. while (ptr != NULL)
  189. {
  190. if (id == ptr->id)
  191. {
  192. flag = 1;
  193. break;
  194. }
  195. ptr = ptr->next;
  196. }
  197. if (flag == 0)
  198. {
  199. puts("没有找到你需要回收的作业!");
  200. return;
  201. }
  202. if (ptr->flag == 0)
  203. {
  204. puts("该ID已经是空闲的了");
  205. return;
  206. }
  207. if (ptr->front == NULL)
  208. {
  209. //第一个分区
  210. if (ptr->next == NULL || ptr->next->flag == 1)
  211. {
  212. //后面不空或后面没有
  213. ptr->flag = 0;
  214. return;
  215. }
  216. if (ptr->next->flag == 0)
  217. {
  218. //后面空
  219. ptr->size += ptr->next->size;
  220. ptr->flag = 0;//标记为空闲
  221. if (ptr->next->next != NULL)//把下一个节点的头指向该节点
  222. {
  223. ptr->next->next->front = ptr;
  224. }
  225. ptr->next = ptr->next->next;//合并两个节点
  226. free(ptr->next);//真实释放节点
  227. return;
  228. }
  229. }
  230. if (ptr->next == NULL)
  231. {
  232. //最后一个分区
  233. if (ptr->front == NULL || ptr->front->flag == 1)
  234. {
  235. //前面不空或者前没有
  236. ptr->flag = 0;
  237. return;
  238. }
  239. if (ptr->front->flag == 0)
  240. {
  241. //前面为空
  242. ptr->front->size += ptr->size;
  243. ptr->front->next = NULL;
  244. free(ptr);
  245. return;
  246. }
  247. }
  248. if (ptr->front->flag == 0 && ptr->next->flag == 0)
  249. {
  250. //上下都空
  251. ptr->front->size += ptr->size + ptr->next->size;
  252. ptr->front->next = ptr->next->next;
  253. if (ptr->next->next != NULL)
  254. {
  255. ptr->next->next->front = ptr->front;
  256. }
  257. changeIdValue(ptr->front->next, -2); //更改id
  258. free(ptr->next);
  259. free(ptr);
  260. return;
  261. }
  262. if (ptr->front->flag == 0 && ptr->next->flag == 1)
  263. {
  264. //上空下不空
  265. ptr->front->size += ptr->size;
  266. ptr->front->next = ptr->next;
  267. ptr->next->front = ptr->front;
  268. changeIdValue(ptr->front->next, -1);
  269. free(ptr);
  270. return;
  271. }
  272. if (ptr->front->flag == 1 && ptr->next->flag == 0)
  273. {
  274. //上不空下空
  275. ptr->size += ptr->next->size;
  276. if (ptr->next->next != NULL)
  277. {
  278. ptr->next->next->front = ptr;
  279. }
  280. partion *p_next = ptr->next; //保存一下下方为空的那个分区,以便一会释放
  281. ptr->next = ptr->next->next;
  282. ptr->flag = 0;
  283. changeIdValue(ptr->next, -1);
  284. free(p_next);
  285. return;
  286. }
  287. if (ptr->front->flag == 1 && ptr->next->flag == 1)
  288. {
  289. //上下都不空
  290. ptr->flag = 0;
  291. return;
  292. }
  293. }.
  294. void changeIdValue(partion *ptr, int delta)
  295. {
  296. while (ptr != NULL)
  297. {
  298. ptr->id += delta;
  299. ptr = ptr->next;
  300. }
  301. }

编译运行截图:

首次适应算法流程图:

最佳适应算法流程图:

内存回收流程图:

首次适应算法,首先用户输入作业需要的内存大小,然后程序从低地址向高地址寻找空间空间,如果找到空闲空间,如果空闲空间的大小比作业需要的空间大则进行分配,如果空闲空间比作业需要的空间小,则继续寻找下一个空闲空间。如果所有的空闲空间都寻找完也没有符合要求的,那么作业的内存分配失败。

最佳适应算法,首页用户输入作业需要的内存空间,程序从低地址开始寻找空闲空间,如果第一次找合适的空间分配,就临时存储这个空间地址,继续向下继续寻找符合的地址空间,如果寻找到合适的空间空间范围,且新的空间大小比临时存储的空间大小还小,则新的符合空间更新为临时符合空间,依次类推到最后。如果程序没有临时最佳的地址空间,则并没有分配到内存,所以作业内存分配失败。如果有临时最佳空间地址,则把最佳的地址空间分配给作业。

作业回收,首先需要需要输入回收作业的ID,先判断作业ID是否存在,存在才能进行释放,在ID存在的前提下判断,该ID的作业状态,只有为已分配状态猜才进行释放。释放则的分情况讨论。释放的节点分为头部,中间,尾部。如果释放的节点前后已经有空闲空间,就需要进行合并。

首次适应算法倾向于优先利用内存中低址部分的空闲分区,从而保留了高址部分的大空闲区,这为以后到达的大作业分配大的内存空间创造了条件。缺点是:低址部分不断被划分,会留下许多难以利用的,很小的空闲分区,称为碎片。而每次查找又都是从低址部分开始的,这无疑又会增加查找可用空闲分区时的开销。

最佳适应算法的一个主要缺点是,空闲区一般不可能正好和要求的大小相等,因而要将其分割成两部分,这往往使剩下的空闲区非常小,以至小到几乎无法使用。换句话说,分割发展下去只能是得到许多非常小的分散的空闲区,造成主存空间的浪费。

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号