标签:
前言
首次适应算法(FF,first fit)是内存基于顺序搜索的动态分配分区算法,在分配内存时,从链首开始顺序查找,直至找到一个大小能满足要求的空闲分区为止,然后在按照作业的大小从该分区中划出一块内存空间,分配给请求者,余下的空闲分区仍留在空闲链中。若从链首直至链尾都不能找到一个能满足要求的分区,则表明系统中已没有足够大的内存分配给该进程,内存分配失败,返回。
该算法倾向于优先利用内存中低地址部分的空闲分区,从而保留了高地址部分不断被划分。这为以后到达的大作业分配大的的内存空间创造了条件。其缺点是低地址部分不断被划分,会留下许多难以利用的、很小的空闲分区,称为碎片。而每次查找又都是从低地址部分开始的,这无疑又会增加查找可用空闲分区时的开销。
这里用JAVA写了一个用首次适应算法来模拟内存分配与回收的程序并配有界面,更加直观的显示了首次适应算法的分配过程。
功能主要有三个模块。第一个内存分配模块,用户根据自己的需要输入进程数,然后分配,每次分配都会有相应的模块号和模块大小情况显示出来再界面上,我们这里模拟的内存容量是十个,所以最多只能分配十个进程。第二个是释放内存模块,在分配时我们已经为每次分配的时候加上了对应的内存块号和内存大小,然后根据模块号,释放掉分配时的内存的大小。第三个是清空内存模块,这里就一个功能就是将内存块回归到初始状态,相当于重启了电脑一样的,内存的东西不在保留,用户可以在根据需要重新分配。
功能结构图:
代码如下:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class Memory extends JFrame {
protected JTextField blank0,blank1,blank2,blank3,
blank4,blank5,blank6,blank7,
blank8,blank9;//定义10个进程块
protected JTextField applyMemTF,releaseMemTF;
protected JTextArea showMemStatusTF;
protected JButton applyMemButton,releaseMemButton,emptyMemButton;
int[] processBlock = new int[10];//表示进程块
int[] processBlockStartAdd = new int[10];//表示存储起始地址
int[] processBlockLength = new int[10];//表示存储进程长度
public Memory() {
JPanel p1 = new JPanel(new GridLayout(3,2,5,2));
p1.add(applyMemButton = new JButton("申请(大小)"));
p1.add(applyMemTF = new JTextField(3));
p1.add(releaseMemButton = new JButton("释放(块号)"));
p1.add(releaseMemTF = new JTextField(3));
p1.add(new Label("\t内存分配情况"));
JPanel p2 = new JPanel(new GridLayout(2,1,2,2));
p2.add(p1);
p2.add(showMemStatusTF = new JTextArea());
JPanel p3 = new JPanel(new GridLayout(11,1,20,0));
p3.add(new JLabel("内存容量为10"));
p3.add(blank0 = new JTextField(3));
p3.add(blank1 = new JTextField(3));
p3.add(blank2 = new JTextField(3));
p3.add(blank3 = new JTextField(3));
p3.add(blank4 = new JTextField(3));
p3.add(blank5 = new JTextField(3));
p3.add(blank6 = new JTextField(3));
p3.add(blank7 = new JTextField(3));
p3.add(blank8 = new JTextField(3));
p3.add(blank9 = new JTextField(3));
JPanel p4 = new JPanel(new BorderLayout(3,3));
p4.add(p2,BorderLayout.WEST);
p4.add(p3,BorderLayout.CENTER);
JPanel p5 = new JPanel(new FlowLayout());
p5.add(p4);
p5.add(emptyMemButton = new JButton("清空内存"),BorderLayout.EAST);
setLayout(new FlowLayout(FlowLayout.CENTER,10,20));
this.getContentPane().add(p5);
Font font1 = new Font("SansSerif",Font.BOLD,16);
applyMemTF.setFont(font1);
releaseMemTF.setFont(font1);
showMemStatusTF.setFont(font1);
applyMemButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int n = Integer.parseInt(applyMemTF.getText());//进程块的大小
if(n > 10 || n <0){
JOptionPane.showMessageDialog(null,"进程大小违规,请重新输入!");
}
outer://向内存中添加进程
for(int i = 0;i < 10; i++ ){//向内存中添加进程
if(processBlock[i] == 0 && Sum(processBlock,i,n) == 0){
processBlockStartAdd[i] = i;//存储起始地址
processBlockLength[i] = n;//存储进程长度
for(int ss = i;ss < (i + n);ss++)
processBlock[ss] = 1;//找到合适的位置,置1
colorr();
JOptionPane.showMessageDialog(null,"成功分配到内存!");
showMemStatusTF.append("块号:" + processBlockStartAdd[i] + " 起始位置:" +
processBlockStartAdd[i] + "大小: " + processBlockLength[i] +"\n");
break outer;
}
if(i == 9){
JOptionPane.showMessageDialog(null,"内存不足,请等待...");
break outer;
}
}
}
});
//释放内存按钮监听
releaseMemButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int m = Integer.parseInt(releaseMemTF.getText());//进程块的起始位置和长度
for(int ff = m;ff < (m + processBlockLength[m]);ff++){
processBlock[ff] = 0;
}
processBlockStartAdd[m] = 0;
processBlockLength[m] = 0;
colorr();
showMemStatusTF.setText("");
for(int bb = 0;bb < 10; bb++){
if(processBlockLength[bb] != 0)
showMemStatusTF.append("块号: " + processBlock[bb] + "起始位置:" +
processBlockStartAdd[bb] + "大小: "+ processBlockLength[bb] + "\n");
}
}
});
//清空内存按钮监听
emptyMemButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
for(int cc = 0;cc < 10;cc++)
processBlock[cc] = 0;
colorr();
applyMemTF.setText("");
releaseMemTF.setText("");
showMemStatusTF.setText("");
}
});
}
//判断内存空间是否足够
public int Sum(int[] pp,int mm,int k){
int sum = 0;
if((mm + k) <= 10){
for(int zz = mm;zz < (mm + k);zz++)
sum+=pp[zz];
}
else {
sum = 1;
}
return sum;
}
//内存与processBlock数组相对应,占用颜色为绿色,空白为蓝色
public void colorr(){
if(processBlock[0]==1)
blank0.setBackground(Color.GREEN);
else
blank0.setBackground(Color.WHITE);
if(processBlock[1]==1)
blank1.setBackground(Color.GREEN);
else
blank1.setBackground(Color.WHITE);
if(processBlock[2]==1)
blank2.setBackground(Color.GREEN);
else
blank2.setBackground(Color.WHITE);
if(processBlock[3]==1)
blank3.setBackground(Color.GREEN);
else
blank3.setBackground(Color.WHITE);
if(processBlock[4]==1)
blank4.setBackground(Color.GREEN);
else
blank4.setBackground(Color.WHITE);
if(processBlock[5]==1)
blank5.setBackground(Color.GREEN);
else
blank5.setBackground(Color.WHITE);
if(processBlock[6]==1)
blank6.setBackground(Color.GREEN);
else
blank6.setBackground(Color.WHITE);
if(processBlock[7]==1)
blank7.setBackground(Color.GREEN);
else
blank7.setBackground(Color.WHITE);
if(processBlock[8]==1)
blank8.setBackground(Color.GREEN);
else
blank8.setBackground(Color.WHITE);
if(processBlock[9]==1)
blank9.setBackground(Color.GREEN);
else
blank9.setBackground(Color.WHITE);
}
public static void main(String[] args){
Memory frame = new Memory();
frame.setTitle("内存模拟分配与回收——首次适应算法");
frame.setSize(500,400);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
首先定义所需要的变量,定义十个变量表示十个进程,接下来就是在内存中为他们分配内存。定义了两个文本框,分别表示用来向内存申请多少块内存以及释放多少块内存。定义个一个显示文本域,用来及时显示内存中分配的情况和释放的情况。定义三个按钮,分别是申请内存按钮、释放内存按钮、清空内存按钮。稍后我们为他们添加监听事件来产生相应的效果。然后定义三个整形数组,大小都为10,一个用来表示进程,一个用来表示进程的存储起始地址,一个用来表示进程的长度。
我们还要做一个程序的界面,在这里我们已经为相应的按钮添加的相应的监听的事件,文本域和文本框也做了相应的设置,详情请见源代码,程序的界面图如下:
我们在申请大小的文本框中输入要分配的进程块,这里输入的是一个字符型的数字,将它解析成整形的数字,然后我们在进行判断,因为我们这里模拟的内存容量为10,所以在输入数字的时候如果大于10或者小于0就违反了进程规定,需要重新输入。输入正确就开始向内存中申请分配内存了,首先看该进程数是否为空,然后我们好重新定义了一个判断内存释放足够的方法, 如果该内存块又为空,内存空间又符合输入的进程数就为它分配,分配之后将进程的数组置为1,然后调用颜色改变的方法,该方法定义了如果该内存的数组的值为1线显示绿色,如果是0就置为白色,就是直观的显示内存的分配情况。再在“内存分配情况”的文本域中打印出内存的相应情况,块号、起始位置、大小的相关数据,这样一次内存的一次分配情况就完成了。
分配之后,内存容量就会产生相应的效果,如果申请的数量大于剩余的的容量的话就会出现内存容量不足的警告,这时候就需要释放内存。在释放内存的文本框中输入要释放的内存块号,同样输入的数字是字符型的需要将它转换成整形,然后在根据输入的内存块号释放掉对应的内存块。模拟的过程是将相应的进程数组置、进程块的起始地址和进程的长度置为0,然后调用颜色改变的方法,将进程数组为0的块的颜色改成白色,再将内存分配情况的文本域的情况撤销掉,重新打印内存分配情况。这样释放内存的步骤就完成了。
经过多次的分配与释放之后可能就会产生一些碎片,即使内存的总容量大于要分配的内存容量,但是因为他们是不连续的,分配时候还是会分配失败,这时候我们就可以将内存清空,重新分配内存。清空内存模拟过成比上面的两个模拟都要简单很多,就是将进程的数组的情况用一个循环从0开始全部置为0,然后调用颜色改变的方法将颜色全都变为绿色,再将申请大小文本框、释放内存文本框、内存分配情况文本域全都置为空就可以了,这样也就是将内存清空的情况模拟过程完成了。
接下来我们来看操作的一些结果:
我们在申请内存框输入3,然后点击“申请(大小)”按钮,结果如下:
可以看到我们已经成功从内存中成功申请到了3块内存。继续在内存分配文本框中输入4,结果如下:
可以看到我们也申请成功了,我们继续在内存分配分本框中输入4,观察结果如下:
这次我们申请失败了,原因肯定就是内存不够用了。接下来我们在“释放(块号)”文本框中输入:3,将块号3释放掉,观察结果:
可以看到我们已经成功将块号为3,大小为4的内存块成功释放点。接下来,点击“清空内存按钮”,观察结果:
点击了之后我们回到了初始状态,就可以继续分配内存了。
标签:
原文地址:http://blog.csdn.net/qq_23381995/article/details/51758137