闲来无事突发奇想写个简单的内存分配器, 考虑到C++ 中的new 操作符可以很轻易的分配内存, delete释放也很方便,但是如果使用C++编写单片机的代码,就不能这样轻易使用new/delete了。其实基于C++的强大,完全可以自己实现new/delete的重载,使用到自己的内存分配。 使用自己的内存分配的好处是,可以在某个已知可用的内存块上随意的进行小块内存的动态分配与释放,这样的话,不仅可以是内存的使用更灵活,也更高效
此篇博文中所涉及的内存分配算法并不保证完全的绝对的高效,但是在平时动态使用内存块的时候却也能提供一定的方便(即使new/delete可用)
此内存块内存分配算法的时间与已分配内存块数目和需要分配内存块大小有关, 释放时间复杂度O(1)
struct MNode
{
unsigned size;
MNode *prev;
MNode *next;
char data[0];
};
class MMU
{
public:
MMU(void * base, unsigned len): base((int *)base), length(len) { init();}
void *alloc(unsigned size) {
unsigned nsize = sizeof(MNode);
unsigned bsize = (size + nsize + 3) & (~0x03u);
MNode *ph = head;
while(ph->next != nullptr) {
unsigned fsize = (unsigned long)ph->next - (unsigned long long)ph;
fsize -= nsize + ph->size;
if(fsize > bsize) break;
ph = ph->next;
}
if(ph->next == nullptr) {
return nullptr;
}
MNode *ret = (MNode *)(((char *)ph) + nsize + ph->size);
ret->size = size;
ret->prev = ph;
ret->next = ph->next;
ret->next->prev = ret;
ret->prev->next = ret;
++(*base);
return ret->data;
}
void free(void *ptr) {
MNode *node = (MNode *)((char *)ptr - sizeof(MNode));
if(node <= head || node >= tail) {
return;
}
if(node->prev->next == node->next
&& node->next->prev == node->prev) {
return;
}
node->prev->next = node->next;
node->next->prev = node->prev;
--(*base);
}
private:
void init() {
*base = 0;
head = (MNode *)(base + 1);
tail = (MNode *)(base + length / sizeof(int)) - 1;
head->size = 0;
head->next = tail;
head->prev = nullptr;
tail->size = 0;
tail->prev = head;
tail->next = nullptr;
}
private:
int *base;
unsigned length;
MNode *head;
MNode *tail;
};
以下是测试代码
int buffer[4096];
int main(int argc, char **argv)
{
MMU mmu(buffer, 4096 * sizeof(int));
void *memory = mmu.alloc(64);
std::cout << "新分配地址:" << memory << std::endl;
void *memory1 = mmu.alloc(16);
std::cout << "新分配地址:" << memory1 << std::endl;
mmu.free(memory);
void *memory2 = mmu.alloc(20);
void *memory3 = mmu.alloc(16);
std::cout << "新分配地址:" << memory2 << std::endl;
std::cout << "新分配地址:" << memory3 << std::endl;
mmu.free(memory2);
mmu.free(memory3);
mmu.free(memory1);
return 0;
}