メモリの割り当てと回復
北京師範大学、珠海
目的
1. ビットマップまたはフリー リストを使用して、メモリ使用量を追跡し、さまざまなメモリ割り当てアルゴリズムをシミュレートおよび評価します。
2. メモリ割り当てとリサイクル管理プロセスに精通している。
実験要件
1. 使い慣れたプログラミング言語でメモリ割り当てとリカバリのシミュレーション プログラムを作成してデバッグし、main 関数でテストする必要があります。
2. 実験レポートには、設計案、データ定義(詳細な説明を含む)、処理手順(アルゴリズムの詳細な説明とアルゴリズムのフローチャート)、ソースコード、動作結果、経験などを含める必要があります。
3. 4 つのメモリ割り当てアルゴリズムのうち少なくとも 2 つをシミュレートする必要があります: 最初の適合、次の適合、最適な適合、および最悪の適合。
4. 各割り当てと回復後の空きパーティション チェーンの状況とメモリ使用図を表示する必要があります。
5. (オプション:) 2 つのパフォーマンス パラメータを計算します。フラグメントの数 (2 ユニット未満の空き領域の数) と、メモリ割り当てを完了するための空き領域の比較 (検索) の数です。数回の比較後の比較回数 要求されたメモリ割り当て。
実験的な内容
メモリ容量が 256KB で、1KB ブロックに分割されているとします。つまり、各メモリ ユニットは 1KB です。プロセスに必要なメモリは 3 ~ 10 ユニットです。同時に、ジョブが必要とするメモリのサイズは、実行中のプロセス中に変化しないと想定されます。
シミュレーションには 3 つの部分が含まれます。
1. 特定のメモリ割り当てアルゴリズムを実現する
2. メモリ回復シミュレーションを実現する
3. 各メモリ割り当て戦略に対応するフラグメント数に関する統計 (オプション)
実験手順
1. メモリ空間割り当てテーブルを決定する
1) データ項目の設計
2) 格納構造の決定
メモリ空間割り当てテーブルは、二重連結リストのデータ形式を採用しています
割り当てられた空間ブロックのデータ構造は
次のとおりです。 フォワード ポインタ: 初期値が -1 である前、
ノードの前のノードの位置を指します メモリ内のプロセス ブロックの位置: strtLocation はメモリ ブロックの位置情報を示します
プロセスブロック id: フラグは占有メモリブロック
スペースサイズ: サイズは占有メモリのサイズを示します
後方ポインタ: next の初期値は -1 で、ノードの次のノード位置を示します
フリーブロックのデータ構造:
フォワードポインタ: 初期値が -1 になる前、フリーブロックの前のフリーブロックの位置を指している
メモリ内のフリーブロックの位置: strtLocation は、
フリーブロックの位置情報空間を示しますblock: size は空き領域を示します backward pointer のサイズ
: next の初期値は -1 で、ノードの次の空きブロックの位置を示します
ジョブ ブロック リンク リストのデータ構造
フリーブロックリストのデータ構造
2. 2 つのアルゴリズムを使用してメモリ空間の割り当てと回復を完了する
1) アルゴリズム解析
2) アルゴリズムフローチャート作成
3) コーディング
4) デバッグ
3. 完了した作業をテストするメイン関数を記述します。
割り当て回復アルゴリズム
1. ファースト フィット アルゴリズム FirstFit - フリー リストはアドレスの昇順でリンクされ、メモリの下位アドレス部分のフリー領域が最初に割り当てられます。上位アドレスと大きな空き領域を確保できます。
2. 巡回適応アルゴリズム NextFit — 前回見つかった空きパーティションの次の空きパーティションから検索します。開始クエリ ポインタが設定されます。このアルゴリズムは、空きパーティションをより均等に分散します。
3. ベスト フィット アルゴリズム BestFit - フリー リンク リストは、パーティション サイズが大きくなる順にリンクされ、条件を満たすメモリ内の最小のフリー エリアが最初に割り当てられます。
4. ワースト フィット アルゴリズム WorstFit - フリー リストはパーティション サイズの降順でリンクされ、メモリ内の最大のフリー エリアが最初に割り当てられます。
達成
1. 最初の適応アルゴリズム
1. コアアイデア
ジョブブロックを割り当てるときは、適切なサイズのメモリブロックが見つかるまで、メモリ内のフリーブロックの位置に従って検索します(フリーブロックのサイズはジョブブロックのサイズ以上です)。
2.難易度分析
メモリ ブロックを再利用する場合、メモリ リストには次の 3 つの状況があります:
(1) 再利用されたブロックの左右に隣接する空きブロックがある;
(2) メモリ ブロックの左側または右側に隣接する空きブロックがある再生ブロック;
(3)リサイクルブロックの左右に隣接するリサイクルブロックがない。
3. 問題解決
ケース (1): 3 つのフリー ブロックをマージする
ケース (2): 隣接する 2 つのフリー ブロックをマージする
ケース (3): フリー リストにフリー ブロックを追加する ケース (3): フリー ブロックをフリー リストに追加する
4.アルゴリズムフローチャート
ジョブ ブロックの割り当て
リサイクル
コード
ProcessNode クラス
//ジョブ ブロックとアイドル ブロックを初期化する
package com.it.bnuz.yzy;
public class ProcessNode {
private int id;
private int size;
public ProcessNode(int id, int size) {
this.id = id;
this.size = size;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
}
UseNode クラス:
//ジョブ ブロック
package com.it.bnuz.yzy;
public class UseNode implements Comparable<UseNode> {
private int before = -1;//初始为-1,-1表示表头
private int startLocation;
private int id;
private int size;
private int next = -1;//初始为-1,-1表示表尾
public UseNode(int id, int size) {
this.id = id;
this.size = size;
}
public int getBefore() {
return this.before;
}
public void setBefore(int before) {
this.before = before;
}
public int getStartLocation() {
return this.startLocation;
}
public void setStartLocation(int startLocation) {
this.startLocation = startLocation;
}
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public int getSize() {
return this.size;
}
public void setSize(int size) {
this.size = size;
}
public int getNext() {
return this.next; }
public void setNext(int next) {
this.next = next;
}
public int compareTo(UseNode o) {
return this.startLocation - o.getStartLocation();
}
public String toString() {
String str = "[before:" + this.before + " startLocation:" + this.startLocation + " id:" + this.id + " size:" + this.size + " next:" + this.next + "]";
return str;
}
}
FreeNode クラス:
// フリー ブロック
package com.it.bnuz.yzy;
public class FreeNode implements Comparable<FreeNode> {
private int before = -1;
private int startLocation;
private int size;
private int next = -1;
public FreeNode(int size) {
this.size = size;
}
public int getBefore() {
return before;
}
public void setBefore(int before) {
this.before = before;
}
public int getStartLocation() {
return startLocation;
}
public void setStartLocation(int startLocation) {
this.startLocation = startLocation;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public int getNext() {
return next;
}
public void setNext(int next) {
this.next = next;
}
@Override
public int compareTo(FreeNode o) {
return this.startLocation - o.getStartLocation();
}
@Override
public String toString() {
String str = "[before:"+before+" startLocation:"+startLocation+" size:"+size+" next:"+next+"]";
return str;
}
}
メモリマップ
private String[] memory_space = new String[256];
初期状態のメモリ状況
// メモリ空間は 16*16 の矩形空間、サイズは 256k、1 単位は 1k を表す
//0 は空き領域を表す
ジョブ リンク リスト:
private List<UseNode> useSpaceList = new ArrayList<>();
フリー リスト:
private List<FreeNode> freeSpaceList = new ArrayList<>();
FirstFit 割り当てアルゴリズム:
/*
*FirstFit首次适应算法 分配算法
* */
void FirstFit_distribution(ProcessNode p){
UseNode useNode = new UseNode(p.getId(),p.getSize());
int size = p.getSize();
int count = 0;
for(int i = 0; i < freeSpaceList.size();i++){
//循环寻找是否有合适大小的空闲块
count++;
if(size <= freeSpaceList.get(i).getSize()){
//先处理空闲快链表
FreeNode freeNode = freeSpaceList.get(i);
useNode.setStartLocation(freeNode.getStartLocation());//插入进的占用块结点的起始位置为这个空闲块的起始位置
if(size < freeNode.getSize()){
//插入块的大小小于该空闲块的大小时,该空闲块的起始位置发生改变,大小发生改变
freeSpaceList.get(i).setStartLocation(freeNode.getStartLocation() + p.getSize());
freeSpaceList.get(i).setSize(freeNode.getSize() - p.getSize());
}
else{
//如果插入块的大小和该空闲块的大小相同,从链表中删除这个空闲块
if(i == 0){
freeSpaceList.get(i+1).setBefore(-1);//如果这个空闲块是表头,那么将下一个空闲块的before置为-1;
}
else{
freeSpaceList.get(i-1).setNext(freeSpaceList.get(i).getNext());
freeSpaceList.get(i+1).setBefore(freeSpaceList.get(i).getBefore());
}
}
//在内存中显示分配情况
for(int j = useNode.getStartLocation();j < useNode.getStartLocation() + useNode.getSize();j++){
if(j == useNode.getStartLocation()){
memory_space[j] = ""+useNode.getId()+" ";
}
else{
memory_space[j] = "+ ";
}
}
showMemory();
//对分配列表进行操作
firstFit_add(useNode);
showUseSpaceList();
showFreeSpaceList();
return;
}
else {
continue;
}
}
if(count == freeSpaceList.size()){
System.out.println("没有合适的空闲块,插入失败");
return;
}
}
割り当てアルゴリズムでは、ジョブ リストを操作するための関数:
firstFit_add(UseNode useNode)
ジョブ リストを挿入する場合、ジョブ リストの位置は次の 3 つの状況に分けられます。
1. ヘッダー
2. 表
3. フッター
/*
* firstFit加入分配空间
* */
private void firstFit_add(UseNode useNode){
//操作占用块链表
useSpaceList.add(useNode);
if(useSpaceList.size() > 1){
useSpaceList.sort(UseNode::compareTo);//通过起始地址号进行排序,模拟插入链表
for(int k = 0;k < useSpaceList.size();k++){
if(useNode.getId() == useSpaceList.get(k).getId()){
if(k == 0){
useSpaceList.get(k).setNext(useSpaceList.get(k+1).getStartLocation());//如果该占用块插到表头,将next指向源列表的表头起始地址
useSpaceList.get(k+1).setBefore(0);//将原表头的before指向表头
}
else if(k == useSpaceList.size()-1){
useSpaceList.get(k).setBefore(useSpaceList.get(k-1).getStartLocation());
useSpaceList.get(k-1).setNext(useSpaceList.get(k).getStartLocation());
}
else{
useSpaceList.get(k).setBefore(useSpaceList.get(k-1).getStartLocation());
useSpaceList.get(k).setNext(useSpaceList.get(k+1).getStartLocation());
useSpaceList.get(k-1).setNext(useSpaceList.get(k).getStartLocation());
useSpaceList.get(k+1).setBefore(useSpaceList.get(k).getStartLocation());
}
}
}
}
}
ファーストフィットリサイクル
/*
* firstFit首次适应算法,内存空间的释放
* 根据分配链表查找到要释放的内存空间地址
* 在空闲内存链表中添加空闲块
* */
public void firstFit_free(int id){
//查找该块的内存块
UseNode free_node = find_useNode(id);
if(free_node != null){
useSpaceList.remove(free_node);
FreeNode freeNode = new FreeNode(free_node.getSize());
freeNode.setStartLocation(free_node.getStartLocation());
freeSpaceList.add(freeNode);
freeSpaceList.sort(FreeNode::compareTo);
for(int i = 0;i < freeSpaceList.size();i++){
if(freeSpaceList.get(i).getStartLocation() == freeNode.getStartLocation()){
if(i == 0){
//如果该空闲块为链表的表头
if((freeNode.getStartLocation() + freeNode.getSize()) == freeSpaceList.get(i+1).getStartLocation()){
//如果两个空闲块相邻,拓展为一块
freeSpaceList.get(i).setSize(freeNode.getSize() + freeSpaceList.get(i).getSize());//合并两个空闲块
if(freeSpaceList.get(i+1).getNext() == -1){
//如果相邻块是最后一个空闲块
freeSpaceList.remove(freeSpaceList.get(i+1));//将相邻空闲块删除
setFreeSpace(freeSpaceList.get(i).getStartLocation(),freeSpaceList.get(i).getSize());
break;
}
else{
freeSpaceList.get(i).setNext(freeSpaceList.get(i+1).getNext());//将空闲块的Next指向相邻块的下一个空闲块
freeSpaceList.get(i+2).setBefore(freeNode.getStartLocation());//将相邻块的下一个空闲块的before指向该空闲块
freeSpaceList.remove(freeSpaceList.get(i+1));
setFreeSpace(freeSpaceList.get(i).getStartLocation(),freeSpaceList.get(i).getSize());
break;
}
}
else{
//如果两个空闲块不相邻
freeSpaceList.get(i).setNext(freeSpaceList.get(i+1).getStartLocation());
freeSpaceList.get(i+1).setBefore(freeSpaceList.get(i).getStartLocation());
setFreeSpace(freeSpaceList.get(i).getStartLocation(),freeSpaceList.get(i).getSize());
}
}
else if(i == (freeSpaceList.size() - 1)){
//如果该空闲块位于链表表尾
FreeNode beforeNode = freeSpaceList.get(i-1);//空闲快的的前结点
if((beforeNode.getStartLocation() + beforeNode.getSize()) == free_node.getStartLocation()){
//如果两个空闲块相邻
freeSpaceList.get(i-1).setSize(beforeNode.getSize() + freeNode.getSize());//合并
freeSpaceList.remove(freeNode);
setFreeSpace(freeNode.getStartLocation(),freeNode.getSize());
break;
}
}
else{
//该空闲块在表中
FreeNode beforeNode = freeSpaceList.get(i-1);
FreeNode nextNode = freeSpaceList.get(i+1);
//分三种情况讨论:三个空闲块都相邻;只与左或右节点相邻;都不相邻
//都相邻
if((beforeNode.getStartLocation() + beforeNode.getSize() == freeNode.getStartLocation()) && (freeNode.getStartLocation() + freeNode.getSize() == nextNode.getStartLocation())){
freeSpaceList.get(i-1).setSize(beforeNode.getSize() + freeNode.getSize() + nextNode.getSize());
freeSpaceList.get(i-1).setNext(nextNode.getNext());
freeSpaceList.remove(freeNode);
freeSpaceList.remove(nextNode);
setFreeSpace(freeNode.getStartLocation(),freeNode.getSize());
break;
}
//与左相邻
else if(beforeNode.getStartLocation() + beforeNode.getSize() == freeNode.getStartLocation()){
freeSpaceList.get(i-1).setSize(beforeNode.getSize()+freeNode.getSize());
setFreeSpace(freeNode.getStartLocation(),freeNode.getSize());
break;
}
//与右相邻
else if(freeNode.getStartLocation() + freeNode.getSize() == nextNode.getStartLocation()){
freeSpaceList.get(i).setSize(freeNode.getSize()+nextNode.getSize());
freeSpaceList.get(i).setBefore(nextNode.getBefore());
freeSpaceList.get(i).setNext(nextNode.getNext());
freeSpaceList.remove(nextNode);
setFreeSpace(freeNode.getStartLocation(),freeNode.getSize());
break;
}
//都不相邻
else{
freeSpaceList.get(i).setBefore(beforeNode.getStartLocation());
freeSpaceList.get(i).setNext(nextNode.getStartLocation());
setFreeSpace(freeNode.getStartLocation(),freeNode.getSize());
break;
}
}
}
}
showMemory();
showUseSpaceList();
showFreeSpaceList();
}
}
リサイクル ブロックの情報関数をクエリし、UseNode オブジェクトを返す
/*
* 通过分配链表useSpaceList查询内存块,返回该内存快的信息
* */
private UseNode find_useNode(int id){
for(int i = 0;i < useSpaceList.size();i++){
if(useSpaceList.get(i).getId() == id){
if(useSpaceList.size() > 1){
if(i == useSpaceList.size()-1){
useSpaceList.get(i-1).setNext(-1);
}
else if(i == 0){
useSpaceList.get(i+1).setBefore(-1);
}
else {
useSpaceList.get(i-1).setNext(useSpaceList.get(i).getNext());
useSpaceList.get(i+1).setBefore(useSpaceList.get(i).getBefore());
}
}
return useSpaceList.get(i);
}
}
return null;
}
結果が示す
ジョブ ブロックの割り当て
ID を入力してください: 1
占有メモリ サイズを入力してください: 35
ID を入力してください: 2
占有メモリ サイズを入力してください: 85
ID を入力してください: 3
占有メモリ サイズを入力してください: 9
ID を入力してください: 4
占有メモリ サイズを入力してください: 21
ID を入力してください: 5
占有メモリ サイズを入力してください: 19
ID を入力してください: 6
占有メモリ サイズを入力してください: 23
ID を入力してください: 7
占有メモリ サイズを入力してください: 15
ID を入力してください: 8
占有メモリ サイズを入力してください: 3
ID を入力してください: 9
占有メモリ サイズを入力してください: 6
割り当て後のメモリ状況:
割り当てられたジョブ ブロック リンク リスト:
割り当て後の高速リンク リストの解放:
リサイクル
id=5 のジョブ ブロックをリサイクルする
ジョブ リンク リスト:
フリーブロックリスト:
両側に空きブロックがある場合:
リサイクルする前に
リサイクル後
ジョブブロックリスト
無料の高速リンクリスト
再挿入
2. 巡回適応アルゴリズム
1. コアアイデア
フリーブロックリストにマークを付けます。ジョブ ブロックを挿入するときは、前回マークしたフリー ブロックの次のフリー ブロックから挿入する適切なフリー ブロックを検索します。
2. アルゴリズムフローチャート
リサイクル アルゴリズムのプロセスは、最初の適合のプロセスと一致するため、ここでは繰り返されません。
3. コードの実装
nextFit アルゴリズム、ここではコア割り当てアルゴリズムのみを示します。ジョブ リンク リストの挿入とフリー リンク リストの挿入のアルゴリズムは上記と一致しています。
/*
* NextFit算法 循环适应算法
* */
public int nextFit_distribution(ProcessNode p,int flag){
UseNode useNode = new UseNode(p.getId(),p.getSize());
int size = p.getSize();
int count = 0;
for(int i = flag; i < freeSpaceList.size();i++){
//从上一次插入的空闲块的下一个空闲块开始循环寻找是否有合适大小的空闲块
count++;
if(size <= freeSpaceList.get(i).getSize()){
//先处理空闲快链表
FreeNode freeNode = freeSpaceList.get(i);
useNode.setStartLocation(freeNode.getStartLocation());//插入进的占用块结点的起始位置为这个空闲块的起始位置
if(size < freeNode.getSize()){
//插入块的大小小于该空闲块的大小时,该空闲块的起始位置发生改变,大小发生改变
freeSpaceList.get(i).setStartLocation(freeNode.getStartLocation() + p.getSize());
freeSpaceList.get(i).setSize(freeNode.getSize() - p.getSize());
}
else{
//如果插入块的大小和该空闲块的大小相同,从链表中删除这个空闲块
if(i == 0){
freeSpaceList.get(i+1).setBefore(-1);//如果这个空闲块是表头,那么将下一个空闲块的before置为-1;
}
else{
freeSpaceList.get(i-1).setNext(freeSpaceList.get(i).getNext());
freeSpaceList.get(i+1).setBefore(freeSpaceList.get(i).getBefore());
}
}
//在内存中显示分配情况
for(int j = useNode.getStartLocation();j < useNode.getStartLocation() + useNode.getSize();j++){
if(j == useNode.getStartLocation()){
memory_space[j] = ""+useNode.getId()+" ";
}
else{
memory_space[j] = "+ ";
}
}
showMemory();
//对分配列表进行操作
addSpaceList(useNode);
showUseSpaceList();
showFreeSpaceList();
if(i == freeSpaceList.size()-1){
//如果该空闲块是最后一个空闲块,将flag置为0
flag = 0;
}
else {
//否则将flag指向下一个空闲块
flag = i + 1;
}
return flag;
}
else {
continue;
}
}
if(count == freeSpaceList.size() - flag){
System.out.println("没有合适的空闲块,插入失败");
}
return flag;
}
4. 結果表示
メモリの初期状況と連結リストの状況:
ジョブ ブロックを挿入:
ID を入力してください: 2
占有メモリ サイズを入力してください: 15
挿入するフリーブロックの位置は最初のフリーブロックで、次に挿入するときは2番目のフリーブロックから始めます
2 番目のジョブ ブロックを挿入します。
最後に割り当てられたフリー ブロックの次のフリー ブロックに割り当てられる
サイズ 30 のジョブ チャンクを挿入します。
ID を入力してください: 6
占有メモリ サイズを入力してください: 30
次に挿入し、最初の空きブロックに戻ります
現時点での連結リスト状況