Heap Allocator now commits and releases pages dynamically.
Some checks failed
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, clang, clang++, macos-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Has been cancelled
Some checks failed
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, clang, clang++, macos-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Has been cancelled
Implemented Heap::free Heap::reset() now clears m_usedSize
This commit is contained in:
@@ -87,6 +87,15 @@ private:
|
|||||||
|
|
||||||
// Get the usable size of a block
|
// Get the usable size of a block
|
||||||
size_t getBlockUsableSize(const TLSFBlock* block) const;
|
size_t getBlockUsableSize(const TLSFBlock* block) const;
|
||||||
|
|
||||||
|
// Get the next block, in physical order
|
||||||
|
TLSFBlock* getNextPhysBlock(TLSFBlock* block);
|
||||||
|
|
||||||
|
// Returns true if block is a free block
|
||||||
|
bool isBlockFree(const TLSFBlock* block) const;
|
||||||
|
|
||||||
|
// Return true if block is the last block, in physical order
|
||||||
|
bool isBlockLast(const TLSFBlock* block) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mimir
|
} // namespace mimir
|
||||||
|
|||||||
85
src/heap.cpp
85
src/heap.cpp
@@ -138,7 +138,28 @@ size_t Heap::getUsed() const
|
|||||||
|
|
||||||
size_t Heap::getBlockUsableSize(const TLSFBlock* block) const
|
size_t Heap::getBlockUsableSize(const TLSFBlock* block) const
|
||||||
{
|
{
|
||||||
return (block->size & ~0b11) - 16;
|
return (block->size & ~0b11) - 16ULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
TLSFBlock* Heap::getNextPhysBlock(TLSFBlock* block)
|
||||||
|
{
|
||||||
|
if (isBlockLast(block)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (TLSFBlock*)((std::byte*)block + block->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return true if block is the last block in physical order
|
||||||
|
bool Heap::isBlockLast(const TLSFBlock* block) const
|
||||||
|
{
|
||||||
|
return (block->size & 0b10) == 0b10;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if block is a free block
|
||||||
|
bool Heap::isBlockFree(const TLSFBlock* block) const
|
||||||
|
{
|
||||||
|
return (block->size & 0b01) == 0b01;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Heap::insertFreeBlock(TLSFBlock* block)
|
void Heap::insertFreeBlock(TLSFBlock* block)
|
||||||
@@ -277,6 +298,14 @@ std::byte* Heap::alloc(size_t size)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure that we can commit pages to back the new block
|
||||||
|
// as well as a trailing free block header
|
||||||
|
size_t neededCommit = ((std::byte*)block - m_region.getAddress()) + size + 16ULL + 32ULL;
|
||||||
|
if (!m_region.maybeGrow(std::max(m_minSize, neededCommit))) {
|
||||||
|
// Out of system memory
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
removeFreeBlock(block);
|
removeFreeBlock(block);
|
||||||
|
|
||||||
size_t usableSize = getBlockUsableSize(block);
|
size_t usableSize = getBlockUsableSize(block);
|
||||||
@@ -289,16 +318,17 @@ std::byte* Heap::alloc(size_t size)
|
|||||||
freeBlock->prevPhys = block;
|
freeBlock->prevPhys = block;
|
||||||
freeBlock->prevFree = nullptr;
|
freeBlock->prevFree = nullptr;
|
||||||
freeBlock->nextFree = nullptr;
|
freeBlock->nextFree = nullptr;
|
||||||
if (block->size & 0b10) { // LSB: T, F: T = Last physical block, F = Free block
|
if (isBlockLast(block))
|
||||||
|
{ // LSB: T, F: T = Last physical block, F = Free block
|
||||||
// Block was the last physical block
|
// Block was the last physical block
|
||||||
block->size &= ~0b10;
|
block->size &= ~0b10;
|
||||||
freeBlock->size &= 0b10;
|
freeBlock->size &= 0b10;
|
||||||
}
|
}
|
||||||
block->size -= freeBlock->size & ~0b10;
|
block->size -= freeBlock->size & ~0b11;
|
||||||
insertFreeBlock(freeBlock);
|
insertFreeBlock(freeBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_usedSize += size;
|
m_usedSize += getBlockUsableSize(block);
|
||||||
return (std::byte*)block + 16;
|
return (std::byte*)block + 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,6 +347,49 @@ std::byte* Heap::allocA64(size_t size)
|
|||||||
// Free the allocation at `address`
|
// Free the allocation at `address`
|
||||||
void Heap::free(std::byte* address)
|
void Heap::free(std::byte* address)
|
||||||
{
|
{
|
||||||
|
TLSFBlock* block = (TLSFBlock*)(address - 16ULL);
|
||||||
|
m_usedSize -= getBlockUsableSize(block);
|
||||||
|
|
||||||
|
TLSFBlock* prevPhys = block->prevPhys;
|
||||||
|
if (prevPhys && isBlockFree(prevPhys)) {
|
||||||
|
// The previous block in physical order is a free block.
|
||||||
|
|
||||||
|
// Remove it from the index
|
||||||
|
removeFreeBlock(prevPhys);
|
||||||
|
|
||||||
|
// Resize it to glob together with the block to free
|
||||||
|
prevPhys->size += (block->size & ~0b11);
|
||||||
|
block = prevPhys;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the free block flag and the last block flag
|
||||||
|
block->size &= ~0b11;
|
||||||
|
|
||||||
|
TLSFBlock* nextPhys = getNextPhysBlock(block);
|
||||||
|
if (nextPhys == nullptr) {
|
||||||
|
// This is the last block
|
||||||
|
block->size &= 0b10;
|
||||||
|
} else if (isBlockFree(nextPhys)) {
|
||||||
|
// The next block in physical order is a free block.
|
||||||
|
|
||||||
|
// remove it from the index
|
||||||
|
removeFreeBlock(nextPhys);
|
||||||
|
|
||||||
|
// Resize free'd block to glob together with the nextPhys block
|
||||||
|
block->size += (nextPhys->size & ~0b11);
|
||||||
|
if (isBlockLast(nextPhys)) {
|
||||||
|
block->size &= 0b10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the free'd block to the index
|
||||||
|
insertFreeBlock(block);
|
||||||
|
|
||||||
|
if (isBlockLast(block)) {
|
||||||
|
// Maybe free pages
|
||||||
|
size_t neededSize = ((std::byte*)block - m_region.getAddress()) + 32ULL;
|
||||||
|
m_region.maybeShrink(neededSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset (or initialize) the heap, freeing all memory and potentially releasing comitted pages.
|
// Reset (or initialize) the heap, freeing all memory and potentially releasing comitted pages.
|
||||||
@@ -325,6 +398,10 @@ void Heap::reset()
|
|||||||
// Clear the index, representing no free blocks
|
// Clear the index, representing no free blocks
|
||||||
TLSFIndex* index = (TLSFIndex*)m_region.getAddress();
|
TLSFIndex* index = (TLSFIndex*)m_region.getAddress();
|
||||||
memset(index, 0, sizeof(TLSFIndex));
|
memset(index, 0, sizeof(TLSFIndex));
|
||||||
|
m_usedSize = 0;
|
||||||
|
|
||||||
|
// Free comitted pages except minimum required
|
||||||
|
m_region.resize(m_minSize);
|
||||||
|
|
||||||
// Start with one free block, filling the entire Region
|
// Start with one free block, filling the entire Region
|
||||||
TLSFBlock* block = (TLSFBlock*)(m_region.getAddress() + sizeof(TLSFIndex));
|
TLSFBlock* block = (TLSFBlock*)(m_region.getAddress() + sizeof(TLSFIndex));
|
||||||
|
|||||||
Reference in New Issue
Block a user