SmartOS/Kernel/Heap.cpp

145 lines
4.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "Kernel\Sys.h"
#include "Interrupt.h"
#include "Heap.h"
#include "TTime.h"
#define MEMORY_ALIGN 4
// 当前堆
const Heap* Heap::Current = nullptr;
/*
堆分配原理:
1使用内存块记录当前块已使用大小以及下一块地址形成内存块链表
2每个内存块剩余空间是下一块指针减去当前块指针再减去已用大小
3初始化第一个内存块已使用0
4申请内存时从第一块开始找空余空间大于等于目标大小的内存块割下来作为链表新节点
5释放内存时找到所在块然后当前块上一块的Next指针直接指向当前块的下一块地址移除当前节点
*/
/******************************** MemoryBlock ********************************/
// 内存块。大小和下一块地址
typedef struct MemoryBlock_
{
int Used;
struct MemoryBlock_* Next;
} MemoryBlock;
/******************************** Heap ********************************/
Heap::Heap(uint addr, int size)
{
Current = this;
// 地址对齐
uint end = addr + size;
addr = (addr + MEMORY_ALIGN - 1) & (~(MEMORY_ALIGN - 1));
end = end & (~(MEMORY_ALIGN - 1));
Address = addr;
Size = end - addr;
// 第一块内存块
auto mb = (MemoryBlock*)addr;
mb->Used = sizeof(MemoryBlock);
mb->Next = (MemoryBlock*)(end - sizeof(MemoryBlock));
mb->Next->Used = sizeof(MemoryBlock);
mb->Next->Next = nullptr;
_Used = sizeof(MemoryBlock) << 1;
_Count = 0;
// 记录第一个有空闲内存的块,减少内存分配时的查找次数
_First = mb;
debug_printf("Heap::Init(0x%p, %d) Free=%d \r\n", Address, Size, FreeSize());
}
int Heap::Used() const { return _Used; }
int Heap::Count() const { return _Count; }
int Heap::FreeSize() const { return Size - _Used; }
void* Heap::Alloc(int size)
{
// 要申请的内存大小需要对齐
size = (size + MEMORY_ALIGN - 1) & (~(MEMORY_ALIGN - 1));
//debug_printf("Address=%p Size=%d ", Address, Size);
int remain = Size - _Used;
if (size > remain)
{
debug_printf("Heap::Alloc %d > %d (0x%p) 失败Size=%d Used=%d First=%p \r\n", size, remain, remain, Size, _Used, _First);
return nullptr;
}
#if DEBUG
// 检查头部完整性
auto head = (MemoryBlock*)Address;
//assert(_First >= head && head->Used <= Size && (byte*)head + head->Used <= (byte*)head->Next, "堆头被破坏!");
assert(head->Used <= Size && (byte*)head + head->Used <= (byte*)head->Next, "堆头被破坏!");
assert(_Used <= Size, "Heap::Used异常");
#endif
void* ret = nullptr;
int need = size + sizeof(MemoryBlock);
SmartIRQ irq;
for (auto mcb = (MemoryBlock*)_First; mcb->Next != nullptr; mcb = mcb->Next)
{
// 找到一块满足大小的内存块。计算当前块剩余长度
int free = (byte*)mcb->Next - (byte*)mcb - mcb->Used;
if (free >= need)
{
// 割一块出来
auto tmp = (MemoryBlock*)((byte*)mcb + mcb->Used);
tmp->Next = mcb->Next;
tmp->Used = need;
mcb->Next = tmp;
// 记录第一个有空闲内存的块,减少内存分配时的查找次数
_First = tmp;
ret = (byte*)(tmp + 1);
_Used += need;
_Count++;
//debug_printf("Heap::Alloc (%p, %d) First=%p Used=%d Count=%d \r\n", ret, need, _First, _Used, _Count);
return ret;
}
}
if (!ret) debug_printf("Heap::Alloc %d 失败Count=%d Used=%d Free=%d First=%p \r\n", size, _Count, _Used, FreeSize(), _First);
return ret;
}
void Heap::Free(void* ptr)
{
auto prev = (MemoryBlock*)Address;
auto cur = (MemoryBlock*)ptr - 1;
SmartIRQ irq;
for (auto mcb = prev->Next; mcb->Next != nullptr; mcb = mcb->Next)
{
// 找到内存块
if (mcb == cur)
{
_Used -= cur->Used;
_Count--;
// 前面有空闲位置
if (cur <= _First) _First = prev;
//debug_printf("Heap::Free (%p, %d) First=%p Used=%d Count=%d \r\n", ptr, cur->Used, _First, _Used, _Count);
prev->Next = cur->Next;
return;
}
prev = mcb;
}
debug_printf("正在释放不是本系统申请的内存 0x%p \r\n", ptr);
}