目录
背景
1.给进程分配内存空间,操作系统需要记录哪些内存区域被分配出去了,哪些还空着
2.当进程运行结束后,操作系统如何回收内存空间
内存空间的分配
我的大概想法是这样子的:
a.建立自由链表表示自由节点
定义的结构体(空闲链表)里面有进程名,进程的大小,进程的起始地址以及指向下一个进程地址的指针(这样定义的优点在于进程进来方便定义)
同时还可以定义一个数组来表示内存的大小,为了更好直观的表示,我这里定义的是20个,以及已分配空间节点和自由节点头指针作为全局变量
char memory[20]; //全局变量
Node *fre,*used;
typedef struct node{
char processName;
int addr;
int size;
struct node* next;
}Node;//建立链表表示已分配节点和自由节点
b.我们先对数组里面空闲区大小进行初始化,也给它赋一个值作为初始值,同时也给空闲区里面的值进行初始化
为了我们可以直观的看出数组里面空闲区有多少个,因此我们需要利用循环语句来得到想要的结果
void init(){//初始化
int i=0;
for(;i<20;i++)
memory[i]='-'; //内存初始化
fre=(Node*)malloc(sizeof(Node));
fre->addr=0; fre->processName='-';
fre->size=20;
fre->next=NULL;
used=NULL;
}
c.我们现在对空闲区进行初始化以后,就可以利用函数来显示空闲区里面的情况,可能有人不理解为啥不直接在初始化里面进行显示,我们利用显示函数可以动态的更新空闲区是否被进程占用。
void showMemory(){ //显示内存
int i=0;Node*p;
for(;i<20;i++)
printf("%c",memory[i]);
printf("\n自由链表:");
p=fre;
while(p){
printf("起始地址%d,大小%d=>",p->addr,p->size);
p=p->next;
}
printf("\n使用链表:");
p=used;
while(p){
printf("进程名:%c,起始地址:%d,大小:%d=>",p->processName,p->addr,p->size);
p=p->next;
}
printf("\n");
d.现在空闲区的大小都已经分配好了,我们现在就假设有进程要进来,申请分配进程的名字,起始地址和大小,那么怎么将进程一个个分配进去勒,所以要用到我们循环了
void allocMemory(char processName,int begin,int size){ //内存分配的数量
int i;
for(i=begin;i<begin+size;i++)
memory[i]=processName;
}
e.现在已经确定好了要分配的进程,但是这个进程还没有进入内存里面去,所以我们要做的就是
向内存申请可以存储这个进程的空闲区,分配内存块大小的时候有三种情况
1.一种是空闲区的大小大于进程的大小,就将该进程的内容存储到空闲区中,并将该进程所在的空间移入到已使用区
if(p->size>size){
allocMemory(processName,p->addr,size);
p->size-=size;//分配内存
p->addr+=size;
q=(Node*)malloc(sizeof(Node));
q->addr=p->addr-size;q->processName=processName;
q->size=size;
q->next=used;
used=q;
break;
2.当空闲区的大小刚好等于进程的大小,直接将进程放入空闲区,并将该进程所在的空间移入到已使用区(同时要记得判断是否有前驱节点)
if(p->size==size){ //p->size 是自由内存的大小,size是进程大小
if(pre==0){ //
fre=p->next;
}else{
pre->next=p->next;
}
allocMemory(processName,p->addr,size);
p->processName=processName;
p->next=used;
used=p;
return;
3.当空闲区的大小小于进程的大小,进程申请内存失败。
pre=p;
p=p->next;
printf("进程%c申请内存失败\n",processName);
内存空间的回收
此时我们的内存里面有内存,那么就需要回收进程来释放内存,那么可以怎么样来回收进程呢,我们这里有四种情况
1.当空闲区的大小加上空闲区的起始地址等于进程(回收区)的起始地址时,说明存在前节点(空闲区)可以和回收区合并
if(p->size+p->addr==node->addr){
p->size+=node->size;
f1=0;//这个是前节点标志位,代表前节点是空闲区
break;
2.当回收区的起始地址加上回收区的大小会等于空闲区的起始地址,说明存在后节点(空闲区)可以和回收区合并
//与后节点合并
if(q->addr==node->addr+node->size){
//回收区的起始地址加上回收区的大小会等于空闲区的起始地址
q->size+=node->size;
q->addr=node->addr;
f2=0;//代表后标志位是空闲区,可以合并
3 当空闲区的大小加上使用区的大小再减去进程的大小等于空闲区的大小时,说明进程可以与前后节点进行合并,但是要与1.2不同的是要判断节点q是否有前驱(前驱的优点在于不用再重新新建一个指针来分配空间占用资源)
if (p->size=p->size+q->size-node->size){
if(qre){ //如果有前驱
qre->next=q->next;
free(q);
break; //这行的意思是如果存在就可以结束这个循环,否则会继续往后走
}
else fre->next=q->next; //如果没有前驱
}
//空闲区有两个节点指向fre,通过前驱节点可以把q节点回收掉,这样就是p节点指向空闲区了
4.当前后都不能进行合并时,那么可以直接给进程指向一个新的空闲区
while(f1==1&&f2==1){ //不与前后节点合并
node->next=fre;
fre=node;
}
内存空间的释放
当我们已经回收好了进程的时候,那最后做的一步就是把进程给释放掉,当然也要考虑是否有前驱。
while(p){//如果内存中存在进程P
if(p->processName==processName){
//考虑是否有前驱
if(pre){
pre=p;
pre->next=p->next;
hsMemory(p);
}
else{ //如果没有前驱
used=p->next;
}
break;
如果没有找到该进程的话
pre=p;p->next; //如果p不存在,那么指针就继续往下走
if(!p){
printf("内存无此进程!");
}
}
大概就这样子,最后写一下主程序
int main()
{
init();//内存总量20个单位
showMemory();
applyMemory('A',5);
showMemory();
endProcess('A');
showMemory();
return 0;
}
全代码:
#include <stdio.h>
#include <stdlib.h>
char memory[20]; //全局变量
typedef struct node{
char processName;
int addr;
int size;
struct node* next;
}Node;//建立链表表示已分配节点和自由节点
Node *fre,*used;//已分配节点和自由节点头指针
void init(){//初始化
int i=0;
for(;i<20;i++)
memory[i]='-'; //内存初始化
fre=(Node*)malloc(sizeof(Node));//自由链表初始化
fre->addr=0; fre->processName='-';
fre->size=20;
fre->next=NULL;
used=NULL; //已分配内存链表初始化
}
void showMemory(){ //显示内存
int i=0;Node*p;
for(;i<20;i++)
printf("%c",memory[i]);
printf("\n自由链表:");
p=fre;
while(p){
printf("起始地址%d,大小%d=>",p->addr,p->size);
p=p->next;
}
printf("\n使用链表:");
p=used;
while(p){
printf("进程名:%c,起始地址:%d,大小:%d=>",p->processName,p->addr,p->size);
p=p->next;
}
printf("\n");
}
void allocMemory(char processName,int begin,int size){ //内存分配的数量
int i;
for(i=begin;i<begin+size;i++)
memory[i]=processName;
}
void applyMemory(char processName,int size){ //应用内存
Node *p=fre,*q,*pre=NULL;
while(p){
if(p->size>size){
allocMemory(processName,p->addr,size);
p->size-=size;//分配内存
p->addr+=size;
q=(Node*)malloc(sizeof(Node));
q->addr=p->addr-size;q->processName=processName;
q->size=size;
q->next=used;
used=q;
break;
}if(p->size==size){ //p->size 是自由内存的大小,size是进程大小
if(pre==0){ //
fre=p->next;
}else{
pre->next=p->next;
}
allocMemory(processName,p->addr,size);
p->processName=processName;
p->next=used;
used=p;
return;
}else{
pre=p;
p=p->next;
}
if(!p) printf("进程%c申请内存失败\n",processName);
}
}
void hsMemory(Node *node){//回收内存
int i=1;
Node * p=fre,*q=fre,*pre=NULL,*qre=NULL;int f1=1,f2=1;
for(i=node->addr;i<node->addr+node->size;i++){//清除进程
memory[i]='-';
}
while(f1&&p){ //与前节点合并
if(p->size+p->addr==node->addr){
p->size+=node->size;
f1=0;
break;
}
pre=p;
p=p->next;
while(f2&&q)
if(q->addr=node->addr+node->size){//与后节点合并
q->size+=node->size;
q->addr=node->addr;
f2=0;
break;
}
qre=q;
q=q->next;
while(f1==0&&f2==0){ //与前后节点合并
if (p->size=p->size+q->size-node->size){
if(qre){
qre->next=q->next;
free(q);
break;
}
else fre->next=q->next;
}
pre=p;
p=p->next;
}
while(f1==1&&f2==1){ //不与前后节点合并
node->next=fre;
fre=node;
}
}
}
void endProcess(char processName){ //释放内存资源
node *p=used,*pre=NULL;
while(p){
if(p->processName==processName){
if(pre){
pre=p;
pre->next=p->next;
hsMemory(p);
}
else{
used=p->next;
}
break;
}
else pre=p;p->next; //如果p不存在,那么指针就继续往下走
}
if(!p){
printf("内存无此进程!");
}
}
int main()
{
init();//内存总量20个单位
showMemory();
applyMemory('A',5);
showMemory();
endProcess('A');
showMemory();
return 0;
}