內存管理-夥伴系統

問題重述:

固定和可變分區內存管理方法都存在缺陷。固定分區由於分區數目是固定的,因此限 制了活動進程的個數,而且當可用內存大小與進程內存需求大小不匹配時,內存使用效率非 常低效。而可變分區方法管理起來較爲複雜,而且由於進程鏡像的上下浮動會帶來額外開銷。 夥伴系統是二者的一種折中,兼具固定和可變分區的優點。

在夥伴系統中,內存塊個數和大小是不固定的,但是大小隻能限定爲 2K 個字節,其中 L ≤ K≤ U

l    2L = 最小塊的大小(字節)

l    2U =  最大塊的大小(字節)。通常是整個內存的大小。 開始時,整個可供內存分配的空間被看做一個塊,其大小爲 2U。如果請求的內存大小爲 s, 且 2U-1 < s ≤ 2U,那麼把整個內存,即 2U 分配給它。否則將整個內存空間分爲兩個大小爲 2U-1 的夥伴塊,並將其中的一個暫時分配給該請求。然後再考查,該 2U-1 大小的塊中,條件

2U-2 <s ≤2U-1 是否滿足,若滿足,則將該 2U-1 大小的塊正式分配給該請求,然後退出內存分 配算法;若不滿足,則將該 2U-1 大小的塊繼續一份爲二,產生兩個大小爲 2U-2 的夥伴塊,並 把其中一個暫時分配給該請求。這樣的過程持續下去,直到如下條件滿足時,內存分配算法 退出:

(1) 存在 L< i ≤ U,使得 2i-1 <s ≤ 2i 時,將大小爲 2i 的塊分配給該請求,算法退出;

(2) s≤ 2L 時,把大小爲 2L 的塊分配給該請求,算法退出。

一、類成員變量說明

添加了一個新的靜態成員變量,賦初值爲1,用於表示當前分區節點的編號

static int number =1;

        public int ID; //分區編號
	public int status =0; //分區狀態,1 表示已分配,0 表示空閒
	public int size =0; //分區大小,只能爲2L ~ 2U
	public Chunk leftBuddy = null ; //左夥伴
	public Chunk rightBuddy = null ;//右夥伴
	static int number =1;

二、類成員方法說明

public Chunk();

類的構造方法,每次在生成新的節點時調用構造方法給當前的節點編號,實現每個節點都有唯一的一個編號

public Chunk(){
		this.ID=this.number;
		this.number++;
	}

 

 

 

public void printMemMap();

遍歷二叉樹的所有節點,將二叉樹的分區號、分區狀態、分區大小輸出到控制檯中。

基本思想:採用先序遍歷的方法將每一個節點的信息打印出來,對於當前節點的葉子節點不爲空則打印葉子節點,以此類推

	public void printMemMap() {
		System.out.println("分區號:"+this.ID);
		System.out.println("分區狀態:"+this.status);
		System.out.println("分區大小:"+this.size);
		System.out.println();
		if(this.leftBuddy != null) {
			this.leftBuddy.printMemMap();
			this.rightBuddy.printMemMap();
		}
		

	}

 

 

public int Release(int id);

釋放指定節點所佔用的內存,採用遍歷的方法找到需要釋放內存的節點,當釋放該節點後判斷該節點的兄弟節點是否也爲空,是則合併這兩個節點,否則不能合併

注意:因爲在合併時需要刪除當前節點和其兄弟節點,所以應當用其父節點來訪問當前節點,否則不能夠刪除當前節點和其兄弟節點

//釋放內存並判斷合併節點
	public int Release(int id) {
		// 釋放內存
		if(this.leftBuddy.ID == id) 
			this.leftBuddy.status=0;
		
		if(this.rightBuddy.ID == id)
			this.rightBuddy.status=0;

		// 合併
		if (this.leftBuddy.status==0&&this.rightBuddy.status==0) {
			this.status=0;
			this.leftBuddy = null;
			this.rightBuddy = null;
			System.out.println("合併節點成功");
			return 0;
		}
		// 不能合併
		else {
			System.out.println("不能合併節點");
			return -1;
		}
	
	}

 

 

 

public int Allocate(int size);

根據所需要的內存大小動態分配內存

基本思想:

首先判斷需要分配的內存大小是否在該節點大小的一半到最大值之間,如果是則分配該節點,否則將該節點分成大小小相等的兩個節點,再用子節點來分配,一直重複之前的操作,知道子節點的內存大小爲1k)時。

注意:再分配過程中需要考慮到優先分配左節點還是右節點,只有當做節點都不能滿足分配條件時纔將右節點分解,再進行分配

	public int Allocate(int size) {
		
		if(this.status == 0){//父節點未被佔用
			if(size>this.size/2 && size<=this.size){//大於空間大小的一半,小於該空間大小
				this.status=1;	
				return this.ID;
			}
			else if(size<this.size/2 && this.size/2>=1){//比空間大小一半要小,空間折半後至少爲1k
				int flag;
				this.status=1;
				this.leftBuddy=new Chunk();
				this.rightBuddy=new Chunk();
				this.leftBuddy.size=this.size/2;
				this.rightBuddy.size=this.size/2;
				flag=this.leftBuddy.Allocate(size);
				return flag;
			}
			else
				return -1;

		}
		else if(this.leftBuddy !=null && this.rightBuddy!=null){//父節點被佔用,但子節點有未被佔用的
			int flagl,flagr;
			flagl=this.leftBuddy.Allocate(size);
			if(flagl>0)
				return flagl;
			else{
				flagr =this.rightBuddy.Allocate(size);
				if(flagr >0)
					return flagr;
				else
					return -1;
			}
		}
		else//父節點被佔用,且子節點也被佔用		
			return -1;	
		
	}
	

 

因爲算法不夠優化,還存在一些問題,所以得到的結果和手工計算的還有差別,當在進行小量分配時不會出現錯誤(和手工計算一樣),當二叉樹的深度較大時會出現一些誤差(和手工分配不一樣)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章