操作系统第5次实验报告:内存管理
- 姓名:朱笃信
- 学号:201821121021
- 班级:计算1811
1. 记录内存空间使用情况
用结构体的方式存放进程的起始地址,进程的分区长度,进程编号,与分区状态。
typedef struct LNode{ int address;//表示该分区的起始地址 int length; //表示该分区的长度 int state; //0表示该分区空闲,1表示该分区已分配 int number; //作业的编号 struct LNode *next; }*pLNode;
2. 记录空闲分区
用链表的方式来记录空闲分区,代码同1,区别在于,进程占用的分区对应的状态为1,而空闲分区的状态为0。
typedef struct LNode{ int address;//表示该分区的起始地址 int length; //表示该分区的长度 int state; //0表示该分区空闲,1表示该分区已分配 int number; //作业的编号 struct LNode *next; }*pLNode;
3. 内存分配算法
采用首次适配算法,判断内存链表中的空闲分区的大小是否满足当前进程的需求,如果内存不够:打印内存分配失败。
如果内存大小充足,则从该空闲块中划分出进程大小的分区,并修正空闲分区的起始地址与空闲大小。
void Allocation(pLNode L, int len, int num) { pLNode p = L->next; while (p != NULL) { if (p->state == 0) { //查找空闲分区 if (p->length > len) { //空闲分区大小充足 pLNode l = (pLNode)malloc(sizeof(pLNode)); l->length = p->length - len; //修正分区大小 l->address = p->address + len; //修正分区起始地址 l->state = 0; l->number = 0; l->next = p->next; p->next = l; p->length = len; p->number = num; p->state = 1; printf("内存分配成功!\n"); return; } else if (p->length == len) { p->number = num; p->state = 1; printf("内存分配成功!\n"); return; } } p = p->next; } printf("内存分配失败,没有找到合适的空闲内存块\n"); }
4. 内存释放算法
释放单一进程的信息,查询链表中是否存在将释放的进程,若无输出查无此进程,若有,将该分区的状态更新为空闲。
void Revocation(pLNode L, int num) { pLNode p = L->next; while (p->next != NULL) { if (p->number == num) { p->state = 0; printf("成功撤销编号为%d的作业!\n",num); return; } p = p->next; } printf("撤销作业失败,没有找到编号为%d的作业\n", num); }
更新链表:查询链表中是否存在相邻的两个空闲进程,将这两个空闲进程进行合并,否则可能由于某一分区大小过小导致其他进程无法使用,造成空间浪费。
void refresh(pLNode L){ pLNode p = L->next; pLNode temp; while(p != NULL){ if(p->next != NULL){ if(p->state == 0 && p->next->state == 0){ temp=p->next; p->length=p->length+temp->length; p->next=temp->next; free(temp); continue; } } p = p->next; } }
5. 运行结果
(1)产生测试数据
srand((unsigned)time(NULL)); //避免较短时间内生成的随机数一样 pLNode L = (pLNode)malloc(sizeof(pLNode)); InitLNode(L, 512); //初始化内存大小 int len, num; int a=0; for(a=0;a<10;a++){ //随机生成10组数据 len=rand()%100; //随机生成进程长度进行测试 Allocation(L,len,1); //创建进程分区 len=rand()%100; Allocation(L,len,2); len=rand()%100; Allocation(L,len,3); print(L); Revocation(L,1); //删除进程分区 Revocation(L,2); Revocation(L,3); refresh(L); //更新链表情况 }
(2)解释结果
初始运行时初始化链表,表头的节点定义为root,root进程大小为8,初始地址为0,状态显示为已分配
然后随机生成三个进程大小的进程,此处为52,17,1,则对应初始地址为:8、60、77,那么剩下的空闲分区为起始地址为78,剩余内存为434,显示状态为空闲,然后将这些进程删除,依次将这些进程对应的分区状态更改为空闲,然后使用refresh函数更新链表情况,将同样空闲的分区合并。
例如下图:
(此处代码未修正,root显示为操作系统)
此图中的第一个3进程未释放,然后创建了大小分别为68、63、57的三个进程,先分配进程1,占用8-76对应的内存,与原进程3间剩下大小为30的空闲分区,不足以让新的进程2与进程3进行使用,而3
之后的空闲分区可以使用,所以2的起始地址为124。新进程3同理。
第二次进行内存分配:
由于此处的分配是在先前三个进程都删除的情况下,所以进程1的起始是从8开始,各进程依次进行内存占用。
如果更改创建进程与删除进程的顺序,或者某些进程不删除,那么会出现如下情况:
此图可以参照图二,图二中的323进程都未删除,此时再创建3个进程,大小分别为32、11、83,由于第一个三进程的与root进程(此处为操作系统)间的空闲分区为98,可以创建进程一与进程二,而三无法创建在此段空闲分区内,故而延后值323之后。