简易内存池
题目描述
请实现一个简易内存池,根据请求命令完成内存分配和释放。
内存池支持两种操作命令,REQUEST和RELEASE,其格式为:
REQUEST=请求的内存大小 表示请求分配指定大小内存,如果分配成功,返回分配到的内存首地址;如果内存不足,或指定的大小为0,则输出error。
RELEASE=释放的内存首地址 表示释放掉之前分配的内存,释放成功无需输出,如果释放不存在的首地址则输出error。
注意:
- 内存池总大小为100字节。
- 内存池地址分配必须是连续内存,并优先从低地址分配。
- 内存释放后可被再次分配,已释放的内存在空闲时不能被二次释放。
- 不会释放已申请的内存块的中间地址。
- 释放操作只是针对首地址所对应的单个内存块进行操作,不会影响其它内存块。
输入描述
首行为整数 N , 表示操作命令的个数,取值范围:0 < N <= 100。
接下来的N行, 每行将给出一个操作命令,操作命令和参数之间用 “=”分割。
输出描述
请求分配指定大小内存时,如果分配成功,返回分配到的内存首地址;如果内存不足,或指定的大小为0,则输出error
释放掉之前分配的内存时,释放成功无需输出,如果释放不存在的首地址则输出error。
用例1
输入
2
REQUEST=10
REQUEST=20
输出
0
10
用例2
输入
5
REQUEST=10
REQUEST=20
RELEASE=0
REQUEST=20
REQUEST=10
输出
0
10
30
0
说明
第一条指令,申请地址0~9的10个字节内存,返回首地址0
第二条指令,申请地址10~29的20字节内存,返回首地址10
第三条指令,释放首地址为0的内存申请,0~9地址内存被释放,变为空闲,释放成功,无需输出
第四条指令,申请20字节内存,09地址内存连续空间不足20字节,往后查找到3049地址,返回首地址30
第五条指令,申请10字节,0~9地址内存空间足够,返回首地址0
解析
知识点:
磁盘空闲分区管理
在操作系统中,空闲分区表和空闲分区链是磁盘管理中的两个重要概念,用于记录磁盘上可用的空闲空间。
-
空闲分区表(Free Space Table):
- 空闲分区表是一个数据结构,用于记录磁盘上各个分区的空闲空间情况。
- 通常,空闲分区表会列出每个分区的起始位置、大小和是否空闲等信息。
- 空闲分区表的更新通常在分配或释放空间时进行,以确保其准确反映了磁盘的空闲空间情况。
-
空闲分区链(Free Space List):
- 空闲分区链是一种数据结构,用于维护磁盘上空闲空间的逻辑顺序。
- 空闲分区链中的每个节点表示一个连续的空闲区域,节点间通过指针连接起来。
- 当需要分配空间时,操作系统可以遍历空闲分区链以找到满足分配要求的空闲区域,然后进行分配。
- 分配或释放空间时,空闲分区链也需要相应地更新,确保链表的连续性和正确性。
-
位视图法
使用标志为1 未使用标志为0
C++
#include <iostream>
#include <sstream>
#include <unordered_map>
#include <vector>
#include <algorithm>
using namespace std;
const int MEMORY_POOL_SIZE = 100;
class MemoryPool {
private:
char memory[MEMORY_POOL_SIZE];
unordered_map<int, int> allocated; //已经分配的分区表
vector<pair<int, int>> freeBlocks; //空闲分区表
public:
MemoryPool() {
freeBlocks.push_back({0, MEMORY_POOL_SIZE});
}
string requestMemory(int size) {
if (size <= 0) {
return "error";
}
for (auto& block : freeBlocks)
{
if (block.second >= size) {
int startIndex = block.first;
block.first += size;
block.second -= size;
if (block.second == 0) {
freeBlocks.erase(remove_if(freeBlocks.begin(), freeBlocks.end(),
[&block](const auto& b){ return b == block; }), freeBlocks.end());
}
allocated[startIndex] = size;
return to_string(startIndex);
}
}
return "error";
}
string releaseMemory(int startIndex) {
auto it = allocated.find(startIndex);
if (it == allocated.end()) {
return "error";
}
int size = it->second;
allocated.erase(it);
addFreeBlock(startIndex, size);
return "";
}
void addFreeBlock(int startIndex, int size) {
auto it = freeBlocks.begin();
while (it != freeBlocks.end() && it->first < startIndex) { //找到插入的位置
++it;
}
if (it != freeBlocks.begin() && prev(it)->first + prev(it)->second == startIndex) {
prev(it)->second += size;
startIndex = prev(it)->first;
size = prev(it)->second;
freeBlocks.erase(prev(it));
}
if (it != freeBlocks.end() && startIndex + size == it->first) {
it->first = startIndex;
it->second += size;
} else {
freeBlocks.insert(it, {startIndex, size});
}
}
string processCommand(const string& command) {
stringstream ss(command);
string operation, value;
getline(ss, operation, '=');
getline(ss, value);
if (operation == "REQUEST") {
int size = stoi(value);
string result = requestMemory(size);
return result;
} else if (operation == "RELEASE") {
int startIndex = stoi(value);
return releaseMemory(startIndex);
} else {
return "Invalid operation";
}
}
};
int main() {
int N;
cin >> N;
cin.ignore(); // Ignore the newline character after N
MemoryPool memoryPool;
for (int i = 0; i < N; ++i) {
string command;
getline(cin, command);
string result = memoryPool.processCommand(command);
cout << result << endl;
}
return 0;
}