基于C++ MFC实现动态分区分配存储管理

♻️ 资源

大小: 65.8MB

➡️ 资源下载:https://download.csdn.net/download/s1t16/87453198

动态分区分配存储管理

一、课程设计任务:

动态分区分配存储管理

开发环境:

Visual studio 2013 (编程语言: MFC )

二、课程设计要求:

  • 建立描述内存分配状况的数据结构;
  • 建立描述进程的数据结构;
  • 使用两种方式产生进程:(a)自动产生,(b)手工输入;
  • 在屏幕上显示内存的分配状况、每个进程的执行情况;
  • 建立分区的分配与回收算法,支持紧凑算法;
  • 时间的流逝可用下面几种方法模拟:
    • 按键盘,每按一次可认为过一个时间单位;
    • 响应 WM_TIMER;
  • 将一批进程的执行情况存入磁盘文件,以后可以读出并重放;
  • 支持算法:
    • 首次适应算法、循环首次适应算法、最佳适应算法、最坏适应算法。

三、课程设计目的:

  • 加深理解动态分区分配存储管理的过程;
  • 实现动态分区分区分配算法:
    • 首次适应算法、循环首次适应算法、最佳适应算法:最坏适应算法;
  • 加深对碎片处理方法——内存回收算法,以及紧凑算法的理解,认识其作用,并予以实现。

四、数据结构设计:

4.1 内存分配状况 (Memory.h):

空闲分区表

描述:

在系统中设置一张空闲分区表,用于记录每个空闲分区的情况。每个空闲分区占一个表目,表目中包括进程序号、分区始址及分区的大小等数据项。

实现:

内存分区:

内存空间:

内存总体设计:

4.2 进程 (Process.h)

描述:

  • 手工输入:
    • 进程具有: 进程标识 + 进程所需空间大小
  • 自动产生:
    • 进程具有: 进程标识 + 进程所需空间大小 + 进程所需运行时间

实现:

五、重要算法和设计思路描述:

5.1 首次适应算法 (first fit):

描述

FF 算法要求空闲分区表以地址递增的次序生成。在分配内存时,从首地址开始顺序查找,直至找到一个大小能满足要求的空闲分区为止;然后再按照作业的大小,从该分区中划出一块内存空间分配给请求者, 余下的空闲分区仍留在空闲表中。若从首地址直至尾地址都不能找到一个能满足要求的分区,则此次内存分配失败,返回。

特点

  • 优点:
    • 该算法倾向于优先利用内存中低址部分的空闲分区,从而保留了高址部分的大空闲区。这给为以后到达的大作业分配大的内存空间创造了条件。
  • 缺点:
    • 低址部分不断被划分,会留下许多难以利用的、很小的空闲分区,而每次查找又都是 从低址部分开始,这无疑会增加查找可用空闲分区时的开销。

实现

5.2 循环首次适应算法 (next fit):

描述

在为进程分配内存空间时,不再是每次都从首址开始查找,而是从上次找到的空闲分区的下一个空闲分区开始查找,直至找到一个能满 足要求的空闲分区,从中划出一块与请求大小相等的内存空间分配给作业。为实现该算法,应设置一起始查寻指针,用于指示下一次起始查寻的空闲分区,并采用循环查找方式,即如果最后一个空闲分区的大小仍不能满足要求,则应返回到第一个空闲分区,比较其大小是否满足要求。找到后,应调整起始查寻指针

特点

  • 优点:
    • 该算法能使内存中的空闲分区分布得更均匀,从而减少了查找空闲分区时的开销。
  • 缺点:
    • 缺乏大的空闲分区。

实现

5.3 最佳适应算法 (best fit) :

描述

每次为作业分配内存时,总是把能满足要求、又是最小的空闲分区分配给作业,避免“大材小用”。为了加速寻找,该算法要求将所有的空闲分区按其容量以从小到大的顺序形成一空闲分区表。这样,第一次找到的能满足要求的空闲区,必然是最佳的。

特点

  • 优点:
    • 孤立地看,最佳适应算法似乎是最佳的
  • 缺点:
    • 在宏观上,因为每次分配后所切割下来的剩余部分总是最小的,这样,在存储器中会留下许多难以利用的小空闲区。

实现

5.4 最坏适应算法 (worst fit) :

描述

扫描整个空闲分区表或链表,总是挑选一个最大的空闲区分割给作业使用。该算法要求将所有的空闲分区按其容量以从大到小的顺序形成一空闲分区链,查找时只要看第一个分区能否满足作业要求。

特点

  • 优点:
    • 可使剩下的空闲区不至于太小,产生碎片的几率最小,对中、小作业 有利,同时最坏适应分配算法查找效率很高。
  • 缺点:
    • 会使存储器中缺乏大的空闲分区

实现

5.5 回收算法 (void ReleaseSpace(int ID, int Size)):

描述

当进程释放内存时,系统根据回收区的首址,从空闲区表中找到相应的插入点,此时可能出现以下四种情况之一:

  • 回收区与插入点的前一个空闲分区 F1 相邻接,见图 4-8(a)。此时应将回收区与插入 点的前一分区合并,不必为回收分区分配新表项,而只需修改其前一分区 F1 的大小。
  • 回收分区与插入点的后一空闲分区 F2 相邻接,见图 4-8(b)。此时也可将两分区合并, 形成新的空闲分区,但用回收区的首址作为新空闲区的首址,大小为两者之和。
  • 回收区同时与插入点的前、后两个分区邻接,见图 4-8(c)。此时将三个分区合并, 使用 F1 的表项和 F1 的首址,取消 F2 的表项,大小为三者之和。
  • 回收区既不与 F1 邻接,又不与 F2 邻接。这时应为回收区单独建立一新表项,填写 回收区的首址和大小,并根据其首址插入到空闲链中的适当位置。

实现:

5.6 紧凑算法 (deque Memory::Compact()):

描述

在连续分配方式中,必须把一个系统或用户程序装入一连续的内存空间。如果在系统中只有若干个小的分区,即使它们容量的总和大于要装入的程序,但由于这些分区不相邻 接,也无法把该程序装入内存。

若想把作业装入,可采用的一种方法是:将内存中的所有作业进行移动,使它们全都相邻接,这样,即可把原来分散的多个小分区拼接成一个大分区,这时就可把作业装入该 区。这种通过移动内存中作业的位置,以把原来多个分散的小分区拼接成一个大分区的方 法,称为“拼接”或“紧凑”,见图 4-9(b)。由于经过紧凑后的某些用户程序在内存中的位置发生了变化,此时若不对程序和数据的地址加以修改(变换),则程序必将无法执行。为此, 在每次“紧凑”后,都必须对移动了的程序或数据进行重定位。

实现

5.7 进程产生策略:

手工输入

使用者通过界面,选择创建进程,填入空间申请的大小。

自动产生:

使用者选择自动产生。

会随机生成进程所需空间大小,以及进程执行时间。

关键函数:

通过这两个函数,响应 WM_TIMER

5.8 实现重放:

描述以及实现

内存动态变化过程回放:

  • 保存内存动态变化日志:

  • 根据内存动态变化日志进行展示:

进程动态变化过程回放:

  • 保存进程动态变化日志:

  • 根据进程动态变化日志进行展示:

六、界面设计:

6.1 设计图:

6.2 运行图:

七、程序演示及整体设计:

7.1 进程手工输入:

选择手工输入

创建 4 个进程,所需空间大小分别为:10、10、20、20

回收进程 1

回放

碎片整理

7.2 进程自动产生

选择自动产生

执行

回放

碎片整理

八、参考文献:

  • 汤小丹、梁红兵、哲凤屏、汤子瀛 编著.计算机操作系统(第四版).西安:西安电子科技大学出版社,2014.05
  • Randal E. Bryant,David R.O Hallaren 著.深入理解计算机系统(第二版).北京:机械工业出版社,2015.04
  • 孙鑫, 余安萍编著. VC++ 深入详解.北京:电子工业出版社,2006

九、附代码:

10.1 DynamicMemoryManagementDlg.h : 头文件

// DynamicMemoryManagementDlg.h : 头文件
//
 
#pragma once
#include "afxwin.h"
#include "Memory.h"
#include "Process.h"
#include <map>
#include "afxcmn.h"
#include <fstream>
#include <windows.h>
#include <ctime>
#include <iostream>
#include <algorithm>
 
 
struct ProcessMemVar
{
	int ID;
	int Size;
	int Time;
	int selType;
};
 
// CDynamicMemoryManagementDlg 对话框
class CDynamicMemoryManagementDlg : public CDialogEx
{
// 构造
public:
	CDynamicMemoryManagementDlg(CWnd* pParent = NULL);	// 标准构造函数
 
// 对话框数据
	enum { IDD = IDD_DYNAMICMEMORYMANAGEMENT_DIALOG };
 
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持
 
 
// 实现
protected:
	HICON m_hIcon;
 
	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:
	afx_msg void OnCbnSelchangeoperatingmode();
	// 选择进程产生方式
	CComboBox m_operatingMode;
	// 选择分配算法
	CComboBox m_SelectAlgorithm;
	afx_msg void OnBnClickedExecute();
	// 手工创建进程空间大小
	//CEdit m_InitialSize;
private:
	Memory Mem;
	int slcAlg;
	ofstream outFile;
	const string FileProcessLog = "ProcessLog";
public:
	afx_msg void OnCbnSelchangeProcessid();
public:
	deque<Process> deqProcess;
	Process ProTmp;
	// 进程ID
	CComboBox m_ProcessID;
	void Display(deque<Partition> deqMem);
	void DisplayProcessList(deque<ProcessMemVar> deqProcessVar);
	void InsertProcessList(int ID, int Size);
	void DeleteProcessList(int ID);
	void ChangeProcessList(int ID, int Size);
	int Cbmm_ProcessIDIndex;
	// 改变进程空间大小
	CEdit m_ChangeSize;
	map<int, int> mapIDtoSize;
	afx_msg void OnBnClickedDefrag();
	//afx_msg void OnLvnItemchangedList1(NMHDR *pNMHDR, LRESULT *pResult);
	// 显示进程情况
	CListCtrl m_ProcessLIST;
	afx_msg void OnLvnItemchangedProcesslist(NMHDR *pNMHDR, LRESULT *pResult);
	afx_msg void OnBnClickedProcessstop();
	afx_msg void OnBnClickedReplay();
	afx_msg void OnBnClickedReset();
	void OnDraw(CDC* pDC, CRect rt, int x, int y, int z);
	// 终止进程
	CButton m_ProcessStop;
	void CDynamicMemoryManagementDlg::InsertProcessList(int ID, int Size, int Time);
	afx_msg void OnTimer(UINT_PTR nIDEvent);
	// 回放
	CButton m_RePlay;
	void getLog();
	void getLogForAuto();
	void initListControl();
};

10.2 DynamicMemoryManagementDlg.cpp : 实现文件

// DynamicMemoryManagementDlg.cpp : 实现文件
//
 
#include "stdafx.h"
#include "DynamicMemoryManagement.h"
#include "DynamicMemoryManagementDlg.h"
#include "afxdialogex.h"
 
 
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
 
 
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
 
class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();
 
// 对话框数据
	enum { IDD = IDD_ABOUTBOX };
 
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
 
// 实现
protected:
	DECLARE_MESSAGE_MAP()
};
 
CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}
 
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}
 
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
 
 
// CDynamicMemoryManagementDlg 对话框
 
 
 
CDynamicMemoryManagementDlg::CDynamicMemoryManagementDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CDynamicMemoryManagementDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	slcAlg = 0;
	outFile.open(FileProcessLog);
	if (!outFile) {
		cerr << "Open Error!" << endl;
		exit(1);
	}
}
 
void CDynamicMemoryManagementDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_operatingMode, m_operatingMode);
	DDX_Control(pDX, IDC_SelectAlgorithm, m_SelectAlgorithm);
	//DDX_Control(pDX, IDC_InitialSize, m_InitialSize);
	DDX_Control(pDX, IDC_ProcessID, m_ProcessID);
	Cbmm_ProcessIDIndex = 1;
	DDX_Control(pDX, IDC_ChangeSize, m_ChangeSize);
	DDX_Control(pDX, IDC_ProcessLIST, m_ProcessLIST);
	DDX_Control(pDX, IDC_ProcessStop, m_ProcessStop);
	DDX_Control(pDX, IDC_RePlay, m_RePlay);
}
 
BEGIN_MESSAGE_MAP(CDynamicMemoryManagementDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_CBN_SELCHANGE(IDC_operatingMode, &CDynamicMemoryManagementDlg::OnCbnSelchangeoperatingmode)
	ON_BN_CLICKED(IDC_BUTTON3, &CDynamicMemoryManagementDlg::OnBnClickedExecute)
	ON_CBN_SELCHANGE(IDC_ProcessID, &CDynamicMemoryManagementDlg::OnCbnSelchangeProcessid)
	ON_BN_CLICKED(IDC_Defrag, &CDynamicMemoryManagementDlg::OnBnClickedDefrag)
	//ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST1, &CDynamicMemoryManagementDlg::OnLvnItemchangedList1)
	ON_NOTIFY(LVN_ITEMCHANGED, IDC_ProcessLIST, &CDynamicMemoryManagementDlg::OnLvnItemchangedProcesslist)
	ON_BN_CLICKED(IDC_ProcessStop, &CDynamicMemoryManagementDlg::OnBnClickedProcessstop)
	ON_BN_CLICKED(IDC_RePlay, &CDynamicMemoryManagementDlg::OnBnClickedReplay)
	ON_BN_CLICKED(IDC_Reset, &CDynamicMemoryManagementDlg::OnBnClickedReset)
	ON_WM_TIMER()
END_MESSAGE_MAP()
 
 
// CDynamicMemoryManagementDlg 消息处理程序
 
BOOL CDynamicMemoryManagementDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();
 
	// 将“关于...”菜单项添加到系统菜单中。
 
	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);
 
	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}
 
	// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标
 
	// TODO:  在此添加额外的初始化代码
 
	// m_operatingMode
	m_operatingMode.AddString(_T("手工输入"));
	m_operatingMode.AddString(_T("自动产生"));
	m_operatingMode.SetCurSel(0);
 
	// m_SelectAlgorithm
	m_SelectAlgorithm.AddString(_T("首次适应算法"));
	m_SelectAlgorithm.AddString(_T("循环首次适应算法"));
	m_SelectAlgorithm.AddString(_T("最佳适应算法"));
	m_SelectAlgorithm.AddString(_T("最坏适应算法"));
	m_SelectAlgorithm.SetCurSel(0);
 
	// m_ProcessID
	m_ProcessID.AddString(_T("创建ID中..."));
	m_ProcessID.SetCurSel(0);
 
	// 初始化 ProcessList
 
	CRect rect;
	m_ProcessLIST.GetClientRect(&rect);
	m_ProcessLIST.SetExtendedStyle(m_ProcessLIST.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
	m_ProcessLIST.InsertColumn(0, _T("ID"), LVCFMT_CENTER, rect.Width() / 2, 0);
	m_ProcessLIST.InsertColumn(1, _T("Size"), LVCFMT_CENTER, rect.Width() / 2, 1);
	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}
 
void CDynamicMemoryManagementDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}
 
// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。
 
void CDynamicMemoryManagementDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文
 
		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
 
		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;
 
		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
		// 描边
		CClientDC dc(this);
		CPen pen(PS_SOLID, 1, RGB(0, 255, 0));
		dc.SelectObject(&pen);
		dc.Rectangle(30, 145, 530, 320);
	}
}
 
void CDynamicMemoryManagementDlg::OnDraw(CDC* pDC, CRect rt, int x, int y, int z) {
	pDC->FillSolidRect(&rt, RGB(x, y, z));//红色填充 
}
 
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CDynamicMemoryManagementDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}
 
 
 
void CDynamicMemoryManagementDlg::OnCbnSelchangeoperatingmode()
{
	// TODO:  在此添加控件通知处理程序代码
	initListControl();
	
}
void CDynamicMemoryManagementDlg::initListControl() {
	if (m_operatingMode.GetCurSel() == 1) {
		if (deqProcess.size() != 0) {
			MessageBox(_T("若想更改进程输入方式,请点击重置!"), _T("警告!"), MB_OK);
			m_operatingMode.SetCurSel(0);
			return;
		}
		while (m_ProcessLIST.DeleteItem(0));
		m_ChangeSize.EnableWindow(false);
		m_ProcessStop.EnableWindow(false);
		m_ProcessID.EnableWindow(false);
		m_operatingMode.EnableWindow(false);
		m_RePlay.EnableWindow(false);
		while (m_ProcessLIST.DeleteColumn(0));
		CRect rect;
		m_ProcessLIST.GetClientRect(&rect);
		m_ProcessLIST.SetExtendedStyle(m_ProcessLIST.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
		m_ProcessLIST.InsertColumn(0, _T("ID"), LVCFMT_CENTER, rect.Width() / 3, 0);
		m_ProcessLIST.InsertColumn(1, _T("Size"), LVCFMT_CENTER, rect.Width() / 3, 1);
		m_ProcessLIST.InsertColumn(2, _T("Time"), LVCFMT_CENTER, rect.Width() / 3, 2);
		//SetTimer(1, 1500, NULL);
	}
	else {
		if (deqProcess.size() != 0) {
			MessageBox(_T("若想更改进程输入方式,请点击重置!"), _T("警告!"), MB_OK);
			m_operatingMode.SetCurSel(1);
			return;
		}
		while (m_ProcessLIST.DeleteItem(0));
		m_ChangeSize.EnableWindow(true);
		m_ProcessStop.EnableWindow(true);
		m_ProcessID.EnableWindow(true);
		m_operatingMode.EnableWindow(true);
		m_RePlay.EnableWindow(false);
		while (m_ProcessLIST.DeleteColumn(0));
		CRect rect;
		m_ProcessLIST.GetClientRect(&rect);
		m_ProcessLIST.SetExtendedStyle(m_ProcessLIST.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
		m_ProcessLIST.InsertColumn(0, _T("ID"), LVCFMT_CENTER, rect.Width() / 2, 0);
		m_ProcessLIST.InsertColumn(1, _T("Size"), LVCFMT_CENTER, rect.Width() / 2, 1);
		KillTimer(1);
	}
}
 
// 执行
void CDynamicMemoryManagementDlg::OnBnClickedExecute()
{
	// TODO:  在此添加控件通知处理程序代码
	if (m_operatingMode.GetCurSel() == 0 && m_ProcessID.GetCurSel() == 0) {
		CString str;
		m_ChangeSize.GetWindowTextW(str);
		if (str.IsEmpty() || 0 >= _ttoi(str)) {
			MessageBox(_T("尚未分配所要创建进程空间大小"), _T("警告!"), MB_OK);
			return;
		}
		ProTmp.CreateProcess(_ttoi(str));
		if (!Mem.Allocate(ProTmp.getPSize(), m_SelectAlgorithm.GetCurSel(), ProTmp.getPID())) {
			MessageBox(_T("内存空间不足"), _T("警告!"), MB_OK);
			ProTmp.decrease();
			return;
		}
		deqProcess.push_back(ProTmp);
		InsertProcessList(ProTmp.getPID(), ProTmp.getPSize());
		mapIDtoSize.insert(make_pair(ProTmp.getPID(), ProTmp.getPSize()));
		str.Format(_T("%d"), ProTmp.getPID());
		m_ProcessID.AddString(str);
	}
	
	if (m_operatingMode.GetCurSel() == 0 && m_ProcessID.GetCurSel() != 0) {
		CString str;
		m_ChangeSize.GetWindowTextW(str);
		int toChangeSize = _ttoi(str);
		if (str.IsEmpty() || 0 == toChangeSize) {
			MessageBox(_T("尚未输入需要改变进程空间的大小"), _T("警告!"), MB_OK);
			return;
		}
 
		CString CStringtoChangeID;
		((CComboBox*)GetDlgItem(IDC_ProcessID))->GetWindowText(CStringtoChangeID);
		int toChangeID = _ttoi(CStringtoChangeID);
		if (toChangeSize < 0) {
			toChangeSize = -toChangeSize;			
			if (mapIDtoSize[toChangeID] < toChangeSize){
				MessageBox(_T("释放的空间过大"), _T("警告!"), MB_OK);
				return;
			}
			else{
 
				// 处理 Process
				if (mapIDtoSize[toChangeID] == toChangeSize){
					m_ProcessID.DeleteString(m_ProcessID.FindString(0, CStringtoChangeID));
				}
				for (int i = 0; i < deqProcess.size(); ++i) {
					if (deqProcess[i].getPID() == toChangeID) {
						if (deqProcess[i].getPSize() == toChangeSize) {
							DeleteProcessList(toChangeID);
							deqProcess.erase(deqProcess.begin() + i);
							mapIDtoSize[toChangeID] -= toChangeSize;
							break;
						}
						if (deqProcess[i].getPSize() < toChangeSize) {
							ChangeProcessList(toChangeID, -deqProcess[i].getPSize());
							deqProcess.erase(deqProcess.begin() + i);
							mapIDtoSize[toChangeID] -= deqProcess[i].getPSize();
							--i;
							continue;
						}
						ChangeProcessList(toChangeID, -toChangeSize);
						deqProcess[i].ChangeSize(-toChangeSize);
						mapIDtoSize[toChangeID] -= toChangeSize;
						break;
					}
				}
				// 处理 deqMem
				Mem.ReleaseSpace(toChangeID, toChangeSize);
				if (mapIDtoSize[toChangeID] == 0) {
					mapIDtoSize.erase(mapIDtoSize.find(toChangeID));
				}
			}
		}
		else {
			if (!Mem.Allocate(toChangeSize, m_SelectAlgorithm.GetCurSel(), toChangeID)) {
				MessageBox(_T("内存空间不足"), _T("警告!"), MB_OK);
				return;
			}
			int ans = -1;
			for (int i = 0; i < deqProcess.size(); ++i) {
				if (deqProcess[i].getPID() == toChangeID) {
					ans = i;
					break;
				}
			}
			if (ans == -1) {
				MessageBox(_T("查找进程ID失败"), _T("警告!"), MB_OK);
				return;
			}
			deqProcess[ans].ChangeSize(toChangeSize);
			mapIDtoSize[toChangeID] += toChangeSize;
			ChangeProcessList(deqProcess[ans].getPID(), toChangeSize);
		}
	}
 
	if (m_operatingMode.GetCurSel() == 1) {
		SetTimer(1, 1500, NULL);
		int totalSize = Mem.getMaxSize();
		int ChangeSize;
		srand((unsigned)(time(NULL)));
		if (deqProcess.size() == 0) {
			slcAlg = rand() % 4;
			m_SelectAlgorithm.SetCurSel(slcAlg);
		}
		while (true) {
			ChangeSize = 1 + rand() % 100;
			if (ChangeSize > totalSize){
				break;
			}
			else totalSize -= ChangeSize;
			int setTime = 1 + rand() % 10;
			ProTmp.CreateProcess(ChangeSize, setTime);
			if (!Mem.Allocate(ProTmp.getPSize(), m_SelectAlgorithm.GetCurSel(), ProTmp.getPID())) {
				ProTmp.decrease();
				break;
			}
			deqProcess.push_back(ProTmp);
			InsertProcessList(ProTmp.getPID(), ProTmp.getPSize(), setTime);
		}
		CString strTime;
		int timeTmp;
		int toChangeSize;
		for (int i = 0; i < m_ProcessLIST.GetItemCount(); ++i) {
			strTime = m_ProcessLIST.GetItemText(i, 2);
			timeTmp = _ttoi(strTime);
			--timeTmp;
			if (0 == timeTmp) {
				CString strID = m_ProcessLIST.GetItemText(i, 0);
				for (int j = 0; j < deqProcess.size(); ++j) {
					if (deqProcess[j].getPID() == _ttoi(strID)) {
						toChangeSize = deqProcess[j].getPSize();
						deqProcess.erase(deqProcess.begin() + j);
						getLogForAuto();
					}
				}
				Mem.ReleaseSpace(_ttoi(strID), toChangeSize);
				totalSize += toChangeSize;
				m_ProcessLIST.DeleteItem(i);
				--i;
				continue;
			}
			strTime.Format(_T("%d"), timeTmp);
			m_ProcessLIST.SetItemText(i, 2, strTime);
		}
	}
	Display(Mem.getMemStatus());
}
 
 
void CDynamicMemoryManagementDlg::OnCbnSelchangeProcessid()
{
	// TODO:  在此添加控件通知处理程序代码
}
 
 
void CDynamicMemoryManagementDlg::OnBnClickedDefrag()
{
	// TODO:  在此添加控件通知处理程序代码
	Display(Mem.Compact());
}
 
 
 
void CDynamicMemoryManagementDlg::OnLvnItemchangedProcesslist(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
	// TODO:  在此添加控件通知处理程序代码
	*pResult = 0;
 
	CString strLangName;       
	NMLISTVIEW *pNMListView = (NMLISTVIEW*)pNMHDR;
 
	if (-1 != pNMListView->iItem)        // 如果iItem不是-1,就说明有列表项被选择   
	{
		// 获取被选择列表项第一个子项的文本   
		strLangName = m_ProcessLIST.GetItemText(pNMListView->iItem, 0);
		int nIndex = m_ProcessID.FindStringExact(0, strLangName);
		m_ProcessID.SetCurSel(nIndex);
	}
 
}
 
void CDynamicMemoryManagementDlg::InsertProcessList(int ID, int Size) {
	CString strID, strSize;
	strID.Format(_T("%d"), ID);
	strSize.Format(_T("%d"), Size);
	int pos = m_ProcessLIST.GetItemCount();
	m_ProcessLIST.InsertItem(pos, strID);
	m_ProcessLIST.SetItemText(pos, 1, strSize);
	getLog();
}
 
void CDynamicMemoryManagementDlg::InsertProcessList(int ID, int Size, int Time) {
	CString strID, strSize, strTime;
	strID.Format(_T("%d"), ID);
	strSize.Format(_T("%d"), Size);
	strTime.Format(_T("%d"), Time);
	int pos = m_ProcessLIST.GetItemCount();
	m_ProcessLIST.InsertItem(pos, strID);
	m_ProcessLIST.SetItemText(pos, 1, strSize);
	m_ProcessLIST.SetItemText(pos, 2, strTime);
	getLogForAuto();
}
 
void CDynamicMemoryManagementDlg::DeleteProcessList(int ID) {
	CString strID;
	strID.Format(_T("%d"), ID);
	int len = m_ProcessLIST.GetItemCount();
	for (int i = 0; i < len; ++i) {
		if (strID == m_ProcessLIST.GetItemText(i, 0)) {
			m_ProcessLIST.DeleteItem(i);
		}
	}
	getLog();
}
 
void CDynamicMemoryManagementDlg::ChangeProcessList(int ID, int Size) {
	CString strID, strSize;
	strID.Format(_T("%d"), ID);
	int sizeTmp;
	for (int i = 0; i < m_ProcessLIST.GetItemCount(); ++i) {
		if (strID == m_ProcessLIST.GetItemText(i, 0)) {
			strSize = m_ProcessLIST.GetItemText(i, 1);
			sizeTmp = _ttoi(strSize);
			strSize.Format(_T("%d"), sizeTmp + Size);
			m_ProcessLIST.SetItemText(i, 1, strSize);
		}
	}
	getLog();
}
 
void CDynamicMemoryManagementDlg::OnBnClickedProcessstop()
{
	// TODO:  在此添加控件通知处理程序代码
	CString toStopID;
	m_ProcessID.GetWindowTextW(toStopID);
	if (toStopID == "创建ID中...") {
		MessageBox(_T("请选中ID"), _T("警告!"), MB_OK);
		return;
	}
	int toChangeID = _ttoi(toStopID), toChangeSize = mapIDtoSize[_ttoi(toStopID)];
	for (int i = 0; i < deqProcess.size(); ++i) {
		if (deqProcess[i].getPID() == toChangeID) {
			if (deqProcess[i].getPSize() == toChangeSize) {
				DeleteProcessList(toChangeID);
				deqProcess.erase(deqProcess.begin() + i);
				mapIDtoSize.erase(mapIDtoSize.find(toChangeID));
				break;
			}
		}
	}
	// 处理 deqMem
	m_ProcessID.DeleteString(m_ProcessID.FindString(0, toStopID));
	Mem.ReleaseSpace(toChangeID, toChangeSize);
	Display(Mem.getMemStatus());
}
void CDynamicMemoryManagementDlg::Display(deque<Partition> deqMem) {
	CDC* pDC = this->GetDC();
	// 描边
	CString currentPID;
	CClientDC dc(this);
 
	CPen penGreen(PS_SOLID, 1, RGB(0, 255, 0));
	CPen penRed(PS_SOLID, 1, RGB(255, 0, 0));
 
	for (int i = 0; i < deqMem.size(); ++i) {
		// 根据内存分区中保存的信息,进行画图展示(详见运行图)
		// 内存分区没有被使用
		if (!deqMem[i].Status) {
			dc.SelectObject(&penGreen);
			dc.Rectangle(30 + deqMem[i].Address * 5, 145, 30 + deqMem[i].Address * 5 + deqMem[i].Size * 5, 320);
			CRect rt(30 + deqMem[i].Address * 5, 120, 30 + deqMem[i].Address * 5 + deqMem[i].Size * 5, 145);
			OnDraw(pDC, rt, 240, 240, 240);
		}
		else {
			// 内存分区正在被使用
			dc.SelectObject(&penRed);
			currentPID.Format(_T("%d"), deqMem[i].ID);
			dc.Rectangle(30 + deqMem[i].Address * 5, 145, 30 + deqMem[i].Address * 5 + deqMem[i].Size * 5, 320);
			CRect rt(30 + deqMem[i].Address * 5, 120, 30 + deqMem[i].Address * 5 + deqMem[i].Size * 5, 145);
			OnDraw(pDC, rt, 240, 240, 240);
			SetTextColor(dc, RGB(0, 191, 255));
			SetBkMode(dc, TRANSPARENT);
			TextOut(dc, 30 + deqMem[i].Address * 5 + 0.4*(deqMem[i].Size * 5), 128, currentPID, currentPID.GetLength());
		}
	}
}
// 根据进程动态变化日志进行展示
void CDynamicMemoryManagementDlg::DisplayProcessList(deque<ProcessMemVar> deqProcessVar) {
	// 清空 控件List Control 原来的列表项
	int len = m_ProcessLIST.GetItemCount();
	for (int i = len - 1; i >= 0; --i) {
		m_ProcessLIST.DeleteItem(i);
	}
	for (int i = 0; i < deqProcessVar.size(); ++i) {
		// 将进程中保存的信息,显示在 控件List Control 中
		m_ProcessLIST.SetRedraw(FALSE);
		CString strID, strSize, strTime;
		strID.Format(_T("%d"), deqProcessVar[i].ID);
		strSize.Format(_T("%d"), deqProcessVar[i].Size);
		m_ProcessLIST.InsertItem(i, strID);
		m_ProcessLIST.SetItemText(i, 1, strSize);
		
		// 根据进程产生方式不同,控件List Control显示内容不同
		if (deqProcessVar[i].selType == 1) {
			strTime.Format(_T("%d"), deqProcessVar[i].Time);
			m_ProcessLIST.SetItemText(i, 2, strTime);
		}
		// 刷新显示 控件List Control 
		m_ProcessLIST.SetRedraw(TRUE);
		m_ProcessLIST.Invalidate();
		m_ProcessLIST.UpdateWindow();
	}
}
 
void CDynamicMemoryManagementDlg::OnBnClickedReplay()
{
	// TODO:  在此添加控件通知处理程序代码
	string FileMemlog = Mem.getFileName();
	ifstream inFileMem(FileMemlog);
 
	ifstream inFileProcess(FileProcessLog);
	int listType;
	int changeNum, changeNumMem, changeNumProcess;
	deque<ProcessMemVar> deqTmpProcess;
	ProcessMemVar Prc;
	deque<Partition> deqTmp;
	Partition Ptn;
	while (inFileProcess >> listType) {
		inFileMem >> changeNumMem;
		changeNum = changeNumMem;
		for (int i = 0; i < changeNum; ++i) {
			inFileMem >> Ptn.ID;
			inFileMem >> Ptn.Address;
			inFileMem >> Ptn.Size;
			inFileMem >> Ptn.Status;
			deqTmp.push_back(Ptn);
		}
		Display(deqTmp);
		deqTmp.clear();
		
		inFileProcess >> changeNumProcess;
		changeNum = changeNumProcess;
		for (int i = 0; i < changeNum; ++i) {
			inFileProcess >> Prc.ID;
			inFileProcess >> Prc.Size;
			if (listType) inFileProcess >> Prc.Time;
			Prc.selType = listType;
			deqTmpProcess.push_back(Prc);
		}
		DisplayProcessList(deqTmpProcess);
		deqTmpProcess.clear();
		Sleep(1500);
	}
}
 
 
void CDynamicMemoryManagementDlg::OnBnClickedReset()
{
	// TODO:  在此添加控件通知处理程序代码
	Mem.Distroy();
	deqProcess.clear();
	if (m_operatingMode.GetCurSel() == 1) {
		getLogForAuto();
	}else getLog();
 
	mapIDtoSize.clear();
	// ProcessList
	int len = m_ProcessLIST.GetItemCount();
	
	for (int i = len - 1; i >= 0; --i) {
		CString strID = m_ProcessLIST.GetItemText(i, 0);
		m_ProcessID.DeleteString(m_ProcessID.FindString(0, strID));
		m_ProcessLIST.DeleteItem(i);
	}
	m_operatingMode.SetCurSel(0);
	m_SelectAlgorithm.SetCurSel(0);
	m_ProcessID.SetCurSel(0);
	SetDlgItemText(IDC_ChangeSize, _T(""));
	KillTimer(1);
	m_ChangeSize.EnableWindow(true);
	m_ProcessStop.EnableWindow(true);
	m_ProcessID.EnableWindow(true);
	m_operatingMode.EnableWindow(true);
	m_RePlay.EnableWindow(true);
	Display(Mem.getMemStatus());
}
 
 
 
 
void CDynamicMemoryManagementDlg::OnTimer(UINT_PTR nIDEvent)
{
	// TODO:  在此添加消息处理程序代码和/或调用默认值
	switch (nIDEvent) {
	case 1:{
		OnBnClickedExecute();
		break;
	}
	case 2:{
		break;
	}
 
	}
	
	CDialogEx::OnTimer(nIDEvent);
}
 
 
//保存进程(手工输入)动态变化日志
void CDynamicMemoryManagementDlg::getLog(){
	outFile << m_operatingMode.GetCurSel() << endl; // 记录进程产生方式
	outFile << deqProcess.size() << endl; // 记录进程数目
	for (int i = 0; i < deqProcess.size(); ++i){
		// 记录进程标识,以及占用空间大小
		outFile << deqProcess[i].getPID() << " " << deqProcess[i].getPSize() << endl;
	}
}
//保存进程(自动产生)动态变化日志
void CDynamicMemoryManagementDlg::getLogForAuto(){
	outFile << m_operatingMode.GetCurSel() << endl; 
	outFile << deqProcess.size() << endl;
	for (int i = 0; i < deqProcess.size(); ++i){
		// 记录进程标识,占用空间大小,以及所需执行时间
		outFile << deqProcess[i].getPID() << " " << deqProcess[i].getPSize()
			<< " " << deqProcess[i].getPTime() << endl;
	}
}

10.3 Memory.h

#pragma once
#include <deque>
#include <vector>
#include <fstream>
using namespace std;
 
// 内存分区
struct Partition {
	int ID; // 进程标识
	int Address; // 分区地址
	int Size; // 分区大小
	bool Status; // 忙:true 闲:false
	Partition() {
		ID = -1; // 进程ID默认初值
	}
};
// 为实现BestFit,WorstFit排序,设计的空闲的内存分区的数据结构
struct myNode
{
	int Index; // 空闲的内存分区在内存空间的位置
	int Size; // 空闲的内存分区的大小
};
class Memory
{
private:
	const int totalSize = 100; // 总共的内存空间大小
	const int beginIndex = 0; // 内存空间起始地址
	const int endIndex = 100; // 内存空间结束地址
	int unusedSize; // 内存空间未使用的大小
	int searchPtrForNF; // next fit 查询指针
	deque<Partition> deqMem; // 保存整个内存的状态
	vector<myNode> vecNode; // 保存按空闲内存空间大小排序后的结果
	Partition Ptn; // 内存分区临时变量
	myNode Nd; // 空闲的内存分区临时变量
	bool FirstFit(int Size, int ID); // 首次适应算法
	bool NextFit(int Size, int ID); // 循环首次适应算法
	bool BestFit(int Size, int ID); // 最佳适应算法
	bool WorstFit(int Size, int ID); // 最坏适应算法
	void CreateVec();
	void Increse(); // 递增排序
	void Decrese(); // 递减排序
	
	// 比较函数
	static bool CmpIncrese(const myNode &N1, const myNode &N2);
	static bool CmpDecrese(const myNode &N1, const myNode &N2);
 
	void Merge(int Index); // 合并连续的空闲内存分区
	const string Filelog = "MemLog"; // 内存动态分配日志(为了回放)
	ofstream outFile;
	void getLog(); // 获取内存动态分配日志
public:
	Memory();
	~Memory();
	bool Allocate(int Size, int algType, int ID); // 分配空间
	deque<Partition> getMemStatus(); // 获取内存空间状态
	void ReleaseSpace(int ID, int Size); // 释放内存空间(并完成连续的空闲内存分区的回收)
	deque<Partition> Compact(); // 紧凑算法(碎片整理)
	string getFileName();  // 获取日志文件名
	void Distroy(); // 将内存状态重置
	int getMaxSize(); // 获取总共的内存空间大小
};

10.4 Memory.cpp

#include "stdafx.h"
#include "Memory.h"
#include <algorithm>
#include <iostream>
using namespace std;
 
 
Memory::Memory()
{
	unusedSize = totalSize;
	searchPtrForNF = 0;
	Ptn.Address = 0;
	Ptn.Size = totalSize;
	Ptn.Status = false;
	deqMem.push_back(Ptn);
	outFile.open(Filelog);
	if (!outFile) {
		cerr << "Open Error!" << endl;
		exit(1);
	}
}
 
 
Memory::~Memory()
{
	deqMem.clear();
}
 
bool Memory::Allocate(int Size, int algType, int ID) {
	bool Flag = false;
	if (Size > unusedSize) {
		return false;
	}
	else{
		unusedSize = unusedSize - Size;
	}
	switch (algType)
	{
	case 0:{
		// 首次适应算法
		Flag = FirstFit(Size, ID);
		break;
	}
	case 1:{
		// 循环首次适应算法
		Flag = NextFit(Size, ID);
		break;
	}
	case 2:{
		// 最佳适应算法
		Flag = BestFit(Size, ID);
		break;
	}
	case 3:{
		// 最坏适应算法
		Flag = WorstFit(Size, ID);
		break;
	}
	default:
		break;
	}
	if (Flag) {
		getLog();
	}
	return Flag;
}
 
bool Memory::FirstFit(int Size, int ID) {
	bool isSuccess = false;
	for (int i = 0; i < deqMem.size(); ++i) {
		// 遍历内存空间
		if ((!deqMem[i].Status) && (Size <= deqMem[i].Size)) {
			// 如果空间没被使用,并且大小满足进程所需空间,则使用此空间,否则继续遍历
			if (Size != deqMem[i].Size) {
				// 如果空闲区间大于进程所需空间,则可以将剩下的空间作为一个分区
				Ptn.Address = deqMem[i].Address + Size;
				Ptn.Size = deqMem[i].Size - Size;
				Ptn.Status = false;
				deqMem.insert(deqMem.begin() + i + 1, Ptn);
				// 由于在进程分配内存时可以任意选择动态分区分配算法,所以对查询指针进行更新。
				searchPtrForNF = (i + 1)%deqMem.size();
			}
			// 改变内存状态:已用
			deqMem[i].ID = ID;
			deqMem[i].Size = Size;
			deqMem[i].Status = true;
			isSuccess = true;
			break;
		}
	}
	// 返回进程是否已成功得到其申请的空间
	return isSuccess;
}
bool Memory::NextFit(int Size, int ID) {
	bool isSuccess = false;
	int i = searchPtrForNF;
	int flag = searchPtrForNF;
	// 从查询指针开始,遍历内存空间
	do 
	{
		if ((!deqMem[i].Status) && (Size <= deqMem[i].Size)) {
			// 如果空间没被使用,并且大小满足进程所需空间,则使用此空间,否则继续遍历
			if (Size != deqMem[i].Size) {
				// 如果空闲区间大于进程所需空间,则可以将剩下的空间作为一个分区
				Ptn.Address = deqMem[i].Address + Size;
				Ptn.Size = deqMem[i].Size - Size;
				Ptn.Status = false;
				deqMem.insert(deqMem.begin() + i + 1, Ptn);
				// 由于在进程分配内存时可以任意选择动态分区分配算法,所以对查询指针进行更新。
				searchPtrForNF = (i + 1)%deqMem.size();
			}
			// 改变内存状态:已用
			deqMem[i].ID = ID;
			deqMem[i].Size = Size;
			deqMem[i].Status = true;
			isSuccess = true;
			break;
		}
		// 遍历下一个内存分区
		i = (i + 1) % deqMem.size();
	} while (i != flag);
	// 返回进程是否已成功得到其申请的空间
	return isSuccess;
}
bool Memory::BestFit(int Size, int ID) {
	bool isSuccess = false;
	// 对空闲内存分区,按照空间大小递增顺序进行排序
	Increse();
	for (int m = 0; m < vecNode.size(); ++m) {
		// 遍历空闲内存空间
		int i = vecNode[m].Index;
		if ((!deqMem[i].Status) && (Size <= deqMem[i].Size)) {
			// 如果空间没被使用,并且大小满足进程所需空间,则使用此空间,否则继续遍历
			if (Size != deqMem[i].Size) {
				// 如果空闲区间大于进程所需空间,则可以将剩下的空间作为一个分区
				Ptn.Address = deqMem[i].Address + Size;
				Ptn.Size = deqMem[i].Size - Size;
				Ptn.Status = false;
				deqMem.insert(deqMem.begin() + i + 1, Ptn);
				// 由于在进程分配内存时可以任意选择动态分区分配算法,所以对查询指针进行更新
				searchPtrForNF = (i + 1) % deqMem.size();
			}
			// 改变内存状态:已用
			deqMem[i].ID = ID;
			deqMem[i].Size = Size;
			deqMem[i].Status = true;
			isSuccess = true;
			break;
		}
	}
	vecNode.clear();
	// 返回进程是否已成功得到其申请的空间
	return isSuccess;
}
bool Memory::WorstFit(int Size, int ID){
	bool isSuccess = false;
	// 对空闲内存分区,按照空间大小递减顺序进行排序
	Decrese();
	for (int m = 0; m < vecNode.size(); ++m) {
		// 遍历空闲内存空间
		int i = vecNode[m].Index;
		if ((!deqMem[i].Status) && (Size <= deqMem[i].Size)) {
			// 如果空间没被使用,并且大小满足进程所需空间,则使用此空间,否则继续遍历
			if (Size != deqMem[i].Size) {
				// 如果空闲区间大于进程所需空间,则可以将剩下的空间作为一个分区
				Ptn.Address = deqMem[i].Address + Size;
				Ptn.Size = deqMem[i].Size - Size;
				Ptn.Status = false;
				deqMem.insert(deqMem.begin() + i + 1, Ptn);
				// 由于在进程分配内存时可以任意选择动态分区分配算法,所以对查询指针进行更新
				searchPtrForNF = (i + 1) % deqMem.size();
			}
			// 改变内存状态:已用
			deqMem[i].ID = ID;
			deqMem[i].Size = Size;
			deqMem[i].Status = true;
			isSuccess = true;
			break;
		}
	}
	vecNode.clear();
	// 返回进程是否已成功得到其申请的空间
	return isSuccess;
}
 
 
bool Memory::CmpIncrese(const myNode &N1, const myNode &N2) {
	if (N1.Size == N2.Size) return N1.Index < N2.Index;
	return N1.Size < N2.Size;
}
bool Memory::CmpDecrese(const myNode &N1, const myNode &N2) {
	if (N1.Size == N2.Size) return N1.Index < N2.Index;
	return N1.Size > N2.Size;
}
deque<Partition> Memory::Compact() {
	deque<Partition> deqTmp;
	int mergeSize = 0;
	// 获取需要紧凑的总的空间大小
	for (int i = 0; i < deqMem.size(); ++i) {
		if (!deqMem[i].Status) {
			mergeSize += deqMem[i].Size;
		}
	}
	// 重定位
	Ptn.Address = 0;
	Ptn.Size = mergeSize;
	Ptn.Status = false;
	deqTmp.push_back(Ptn);
	int deqTmpSize = 0;
	for (int i = 0; i < deqMem.size(); ++i) {
		if (deqMem[i].Status) {
			Ptn.ID = deqMem[i].ID;
			Ptn.Address = deqTmp[deqTmpSize].Address + deqTmp[deqTmpSize].Size;
			Ptn.Size = deqMem[i].Size;
			Ptn.Status = true;
			deqTmp.push_back(Ptn);
			++deqTmpSize;
		}
	}
	deqMem.clear();
	deqMem = deqTmp;
	deqTmp.clear();
	getLog();
	return deqMem;
}
 
deque<Partition> Memory::getMemStatus() {
	return deqMem;
}
 
void Memory::ReleaseSpace(int ID, int Size) {
	for (int i = 0; i < deqMem.size(); ++i) {
		// 遍历内存空间,根据内存空间是否使用,以及进程标识确定回收的内存分区
		if (deqMem[i].Status && (deqMem[i].ID == ID)) {
			if (Size == deqMem[i].Size) {
				// 进程回收的内存空间大小 == 当前存储此进程内存分区的空间大小
				// 直接回收
				deqMem[i].Status = false;
				Merge(i); // 对于邻接的空闲内存分区进行合并
				unusedSize += Size;
				break;
			}
			if (Size > deqMem[i].Size) {
				// 进程回收的内存空间大小 > 当前存储此进程内存分区的空间大小
				// 回收此内存分区的空间,并继续寻找需要回收的下一个内存分区
				deqMem[i].Status = false;
				Merge(i); // 对于邻接的空闲内存分区进行合并
				unusedSize += deqMem[i].Size;
				--i;
				continue;
			}
			// 进程回收的内存空间大小 < 当前存储此进程内存分区的空间大小
			// 内存空间中加入新回收的内存分区
			deqMem[i].Size -= Size;
			Ptn.Address = deqMem[i].Address + deqMem[i].Size;
			Ptn.Size = Size;
			Ptn.Status = false;
			deqMem.insert(deqMem.begin() + i + 1, Ptn);
			Merge(i + 1); // 对于邻接的空闲内存分区进行合并
			unusedSize += Size;
			break;
		}
	}
	getLog(); // 记入日志
}
 
void Memory::Merge(int Index) {
	int beginAddress = deqMem[Index].Address;
	int beginIndex = Index, endIndex = Index;
	int j = Index;
	int sizeTmp = 0;
	// 向地址递减方向进行搜索,判断可以合并的空闲内存分区最小地址
	while (j >= 0 && !deqMem[j].Status) {
		beginAddress = deqMem[j].Address;
		beginIndex = j;
		sizeTmp += deqMem[j].Size;
		--j;
	}
	j = Index + 1;
	// 向地址递增方向进行搜索,判断可以合并的空闲内存分区最大地址
	while (j < deqMem.size() && !deqMem[j].Status) {
		endIndex = j;
		sizeTmp += deqMem[j].Size;
		++j;
	}
	// 对查询指针进行更新。
	searchPtrForNF -= (endIndex - beginIndex);
	// 对连续的空闲内存分区进行合并。
	deqMem.erase(deqMem.begin() + beginIndex, deqMem.begin() + endIndex + 1);
	Ptn.Address = beginAddress;
	Ptn.Size = sizeTmp;
	Ptn.Status = false;
	deqMem.insert(deqMem.begin() + beginIndex, Ptn);
}
 
void Memory::Increse() {
	CreateVec();
	sort(vecNode.begin(), vecNode.end(), CmpIncrese);
}
void Memory::Decrese() {
	CreateVec();
	sort(vecNode.begin(), vecNode.end(), CmpDecrese);
}
 
void Memory::CreateVec() {
	for (int i = 0; i < deqMem.size(); ++i) {
		if (!deqMem[i].Status) {
			Nd.Index = i;
			Nd.Size = deqMem[i].Size;
			vecNode.push_back(Nd);
		}
	}
}
 
// 保存内存动态变化日志
void Memory::getLog() {
	outFile << deqMem.size() << endl; // 内存分区的个数
	for (int i = 0; i < deqMem.size(); ++i) {
		// 内存分区中进程标识、内存分区始址、内存分区大小、内存分区状态(是否被使用)
		outFile << deqMem[i].ID << " " << deqMem[i].Address
			<< " " << deqMem[i].Size << " " << deqMem[i].Status 
			<< endl;
	}
}
 
string Memory::getFileName() {
	return Filelog;
}
 
void Memory::Distroy() {
	deqMem.clear();
	unusedSize = totalSize;
	searchPtrForNF = 0;
	Ptn.Address = 0;
	Ptn.Size = totalSize;
	Ptn.Status = false;
	deqMem.push_back(Ptn);
	getLog();
}
 
int Memory::getMaxSize() {
	return totalSize;
}

10.5 Process.h

#pragma once
class Process
{
private:
	/*
	注:
	(1)手工输入:
		进程具有: 进程标识 + 进程所需空间大小
	(2)自动产生:
		进程具有: 进程标识 + 进程所需空间大小 + 进程所需运行时间
	*/
	int PID; // 进程标识
	int PSize; // 进程所需空间大小
	int PTime; // 进程所需运行时间
	int PselType; 
	// 区分进程产生方式:
	// 手工输入:PselType = 0; 
	// 自动产生:PselType = 1;
	int nextID; // 下一个产生进程的标识
public:
	Process();
	~Process();
	void CreateProcess(int Size); //手工输入进程
	void CreateProcess(int Size, int Time);//自动产生进程
	int getPID(); // 获取进程ID
	int getPSize(); // 获取进程大小
	int getPTime(); // 获取进程运行时间
	int getPselType(); // 获取进程产生类型
	void ChangeSize(int ChangeSize); // 改变进程空间大小
	void decrease(); // 纠正进程标识(使进程标识从0连续递增产生)
};

10.6 Process.cpp

#include "stdafx.h"
#include "Process.h"
 
 
Process::Process()
{
	nextID = -1;
}
 
 
Process::~Process()
{
}
 
void Process::CreateProcess(int Size) {
	PID = ++nextID;
	PSize = Size;
	PselType = 0;
}
void Process::CreateProcess(int Size, int Time) {
	PID = ++nextID;
	PSize = Size;
	PTime = Time;
	PselType = 1;
}
 
int Process::getPID() {
	return PID;
}
int Process::getPSize() {
	return PSize;
}
 
int Process::getPTime() {
	return PTime;
}
 
int Process::getPselType() {
	return PselType;
}
 
void Process::ChangeSize(int ChangeSize){
	PSize += ChangeSize;
}
 
void Process::decrease() {
	--nextID;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

神仙别闹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值