java实现:《操作系统实验三》模拟内存管理

固定分区分配

固定分区分配是最简单的一种多道程序存储管理方式,它将用户内存空间划分为若干个固定大小的区域,每个分区只装入一道作业。当有空闲分区时,便可以再从外存的后背作业队列中,选择适当大小的作业装入该分区,如此循环。

在这里插入图片描述
在这里插入图片描述

优缺点:

分区大小相等:用于利用一台计算机控制多个相同对象的场合,缺乏灵活性
分区大小不等:划分为含有多个较小的分区,适量的中等分区及少量的大分区。
优点:1.没有外部碎片
缺点:1.程序可能太大而放不进任何一个分区中,这时用户不得不使用覆盖技术来使用内存空间。
主存利用率低,当程序小于固定分区大小时,也占用一个完整的内存分区空间,这样分区内部有空间浪费,这种现象称为内部碎片。
不能多个进程共享一个主存区

#java模拟实现:

package com.qiu;

import java.util.Collections;
import java.util.Date;

public class mem_a extends Thread{
	public char[] mem;
	//定义内存大小
	public mem_a(int size) {
		mem=new char[size];
		for(int i=0;i<size;i++) {
			mem[i]='_';
		}
	}
	
	@Override
	public void run() {
		while(true) {
			try {
				/**Collections工具类中的nCopies(int n,T o)方法用于返回一个不可变列表组成的n个拷贝的指定对象。
				 * 此处即是将"/n"拷贝100次并以字符串形式放回(模拟内存的读写过程中间的页面刷新)
				 * */
				System.out.println(Collections.nCopies(100, "\n").stream().reduce((a, b)->a+b).get());
				//s1为模拟内存逻辑地址,初始状态还未分配资源全为‘_’
				StringBuffer s1=new StringBuffer("[");
				for(int i=0;i<mem.length;i++) {
					s1.append(mem[i]);
				}
				s1.append("]");
				//s2模拟内存分区大小
				StringBuffer s2=new StringBuffer("[1");
				for(int i=1;i<mem.length-1;i++) {
					s2.append('_');
					if(mem[i]!=mem[i+1]&&i!=0) {
						s2.append(i+1);
						i+=(i+"").length();
					}
				}
				s2.append(mem.length+"]");
				System.out.println(new Date());
				System.out.println(s1);
				System.out.println(s2);
				Thread.sleep(100);
			}catch(Exception e) {
				e.printStackTrace();
			}
		}
	}
	//分配内存方法
	public void allocate(char key,int start,int length) {
		for(int i=start;i<start+length;i++) {
			mem[i]=key;
		}
	}
	//释放内存方法
	public void free(char key) {
		for(int i=0;i<mem.length;i++) {
			if(mem[i]==key) {
				mem[i]='_';
			}
		}
	}
	
	public static void main(String[] args) throws InterruptedException {
		mem_a m=new mem_a(100);
		m.start();
		
		Thread.sleep(3000);
		m.allocate('a', 0, 30);
		Thread.sleep(3000);
		m.allocate('b', 40, 20);
		Thread.sleep(3000);
		m.allocate('a', 80, 20);
		Thread.sleep(3000);
		m.free('b');
		
	}
}

动态分区分配

动态分区分配又称为可变分区分配。这种分配方式不会预先划分内存分区,而是在进程装入内存时,根据进程的大小动态地建立分区,并使分区的大小正好适合进程的需要。因此系统分区的大小和数目是可变的。
在这里插入图片描述

首次适应算法

算法思想:每次都从低地址开始查找,找到第–个能满足大小的空闲分区。

如何实现:空闲分区以地址递增的次序排列。每次分配内存时顺序查找空闲分区链( 或空闲分[表),找到大小能满足要求的第-一个空闲分区。

在这里插入图片描述
java实现:

package com.qiu;

import java.util.Collections;
import java.util.Date;
import java.util.LinkedList;

public class mem_b extends Thread{
	public char[] mem;
	//定义内存大小
	public mem_b(int size) {
		mem=new char[size];
		for(int i=0;i<size;i++) {
			mem[i]='_';
		}
	}

	@Override
	public void run() {
		while(true) {
			try {
				/**Collections工具类中的nCopies(int n,T o)方法用于返回一个不可变列表组成的n个拷贝的指定对象。
				 * 此处即是将"/n"拷贝100次并以字符串形式放回(模拟内存的读写过程中间的页面刷新)
				 * */
				System.out.println(Collections.nCopies(100, "\n").stream().reduce((a, b)->a+b).get());
				//s1为模拟内存逻辑地址,初始状态还未分配资源全为‘_’
				StringBuffer s1=new StringBuffer("[");
				for(int i=0;i<mem.length;i++) {
					s1.append(mem[i]);
				}
				s1.append("]");
				//s2模拟内存分区大小
				StringBuffer s2=new StringBuffer("[1");
				for(int i=1;i<mem.length-1;i++) {
					s2.append('_');
					if(mem[i]!=mem[i+1]&&i!=0) {
						s2.append(i+1);
						i+=(i+"").length();
					}
				}
				s2.append(mem.length+"]");
				System.out.println(new Date());
				System.out.println(s1);
				System.out.println(s2);
				Thread.sleep(100);
			}catch(Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	int lastpos=0;
	LinkedList<Character> waitkey=new LinkedList<>();
	LinkedList<Integer> waitSize=new LinkedList<>();
	
	public boolean allocate(char key,int size) {
		int freemem=0,begin=lastpos;
		boolean quit=false;
		while(true) {
			if(mem[lastpos]=='_') {
				freemem++;
				if(freemem==size) {
					lastpos++;
					for(int i=0;i<size;i++) {
						mem[(i+lastpos-size+mem.length)%mem.length]=key;
					}
					return true;
				}
			}else {
				freemem=0;
				if(quit) {
					break;
				}
			}
			lastpos=(++lastpos)%mem.length;
			if(lastpos==begin) {
				quit=true;
			}
		}
		waitkey.push(key);
		waitSize.push(size);
		return false;
	}
	
	public void free(char key) {
		for(int i=0;i<mem.length;i++) {
			if(mem[i]==key) {
				mem[i]='_';
			}
		}
		int waitnum=waitkey.size();
		for(int i=0;i<waitnum;i++) {
			allocate(waitkey.poll(),waitSize.poll());
		}
	}
	
	public static void main(String[] args) throws InterruptedException {
		mem_b m=new mem_b(100);
		m.start();
		Thread.sleep(3000);
		m.allocate('a', 30);
		Thread.sleep(3000);
		m.allocate('b', 40);
		Thread.sleep(3000);
		m.allocate('c', 50);
		Thread.sleep(3000);
		m.allocate('d', 20);
		Thread.sleep(3000);
		m.free('a');
		Thread.sleep(3000);
		m.free('d');
		
	}
}	

最佳适应算法

算法思想:由于动态分区分配是一种连续分配方式,为各进程分配的空间必须是连续的一整片区域。因此为了保证当“大进程”到来时能有连续的大片空间,可以尽可能多地留下大片的空闲区,即,优先使用更小的空闲区。

如何实现:空闲分区按容量递增次序链接。每次分配内存时顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第-一个空闲分区。
在这里插入图片描述
java实现:

package com.qiu;

import javafx.util.Pair;

import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.LinkedList;

public class mem_c extends Thread{
    public char[] mem;
    //定义内存大小
    public mem_c(int size) {
        mem=new char[size];
        for(int i=0;i<size;i++) {
            mem[i]='_';
        }
    }

    @Override
    public void run() {
        while(true) {
            try {
                /**Collections工具类中的nCopies(int n,T o)方法用于返回一个不可变列表组成的n个拷贝的指定对象。
                 * 此处即是将"/n"拷贝100次并以字符串形式放回(模拟内存的读写过程中间的页面刷新)
                 * */
                System.out.println(Collections.nCopies(100, "\n").stream().reduce((a, b)->a+b).get());
                //s1为模拟内存逻辑地址,初始状态还未分配资源全为‘_’
                StringBuffer s1=new StringBuffer("[");
                for(int i=0;i<mem.length;i++) {
                    s1.append(mem[i]);
                }
                s1.append("]");
                //s2模拟内存分区大小
                StringBuffer s2=new StringBuffer("[1");
                for(int i=1;i<mem.length-1;i++) {
                    s2.append('_');
                    if(mem[i]!=mem[i+1]&&i!=0) {
                        s2.append(i+1);
                        i+=(i+"").length();
                    }
                }
                s2.append(mem.length+"]");
                System.out.println(new Date());
                System.out.println(s1);
                System.out.println(s2);
                Thread.sleep(100);
            }catch(Exception e) {
                e.printStackTrace();
            }
        }
    }

    LinkedList<Character> waitkey=new LinkedList<>();
    LinkedList<Integer> waitSize=new LinkedList<>();
    /*
     * java Pair类的使用场景:
     * 当我们在写一个方法需要返回两个字段值时,我之前的方法是新建一个类或使用集合。目前来看使用Pair方便很多。
             配对(Pair)。配对提供了一种方便方式来处理简单的键值关联,当我们想从方法返回两个值时特别有用。
     */
    LinkedList<Pair<Integer,Integer>> size_start=new LinkedList<>();

    public void updateFreeList() {
        size_start.clear();
        int freecount=0;
        for(int i=0;i<mem.length;i++) {
            if(mem[i]=='_') {
                freecount++;
            }else {
                if(freecount>0) {
                    size_start.add(new Pair<Integer,Integer>(freecount,i-freecount));
                    freecount=0;
                }
            }
        }
        if(freecount>0) {
            size_start.add(new Pair<Integer,Integer>(freecount,mem.length-freecount));
            freecount=0;
        }
        Collections.sort(size_start,new Comparator<Pair<Integer,Integer>>(){
            public int compare(Pair<Integer,Integer> o1,Pair<Integer,Integer> o2) {
                return o1.getKey()-o2.getKey();
            };
        });
    }
    public boolean allocate(char key,int size) {
    	updateFreeList();
        boolean quit=false;
        for(Pair<Integer,Integer> entry:size_start) {
            if(entry.getKey()>=size) {
                for(int i=0;i<size;i++) {
                    mem[entry.getValue()+i]=key;
                }
                updateFreeList();
                quit=true;
                break;
            }
        }
        if(!quit) {
            waitkey.push(key);
            waitSize.push(size);
        }
        return quit;
    }

    public void free(char key) {
        for(int i=0;i<mem.length;i++) {
            if(mem[i]==key) {
                mem[i]='_';
            }
        }
        int waitnum=waitkey.size();
        for(int i=0;i<waitnum;i++) {
            allocate(waitkey.poll(),waitSize.poll());
        }
    }
    public static void main(String[] args) throws InterruptedException {
        mem_c m=new mem_c(100);
        m.start();
        Thread.sleep(3000);
        m.allocate('a', 30);
        Thread.sleep(3000);
        m.allocate('b', 40);
        Thread.sleep(3000);
        m.allocate('c', 50);
        Thread.sleep(3000);
        m.allocate('d', 20);
        Thread.sleep(3000);
        m.free('a');
        Thread.sleep(3000);
        m.free('d');
        Thread.sleep(3000);
        m.allocate('e', 30);
    }
}

关于第三种方式在Eclipse上编译报错的解决方法:

原因:Pair类 javafx.util.Pair无法找到
解决方法:
window->Perferences
在这里插入图片描述
之后再次运行,便ok了

  • 14
    点赞
  • 63
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值