mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 17:07:34 +00:00
LibJS: Implement lazy freelist allocation for cells
HeapBlock now implements the same lazy freelist as LibC malloc() does, where new blocks start out in a "bump allocator" mode that gets used until we've bump-allocated all the way to the end of the block. Then we fall back to the old freelist style as before. This means we don't have to pre-initialize the freelist on HeapBlock construction. This defers page faults and reduces memory usage for blocks where all cells don't get used. :^)
This commit is contained in:
parent
a15c7b7944
commit
c2d9cd8d53
2 changed files with 8 additions and 11 deletions
|
@ -41,15 +41,6 @@ HeapBlock::HeapBlock(Heap& heap, size_t cell_size)
|
||||||
, m_cell_size(cell_size)
|
, m_cell_size(cell_size)
|
||||||
{
|
{
|
||||||
VERIFY(cell_size >= sizeof(FreelistEntry));
|
VERIFY(cell_size >= sizeof(FreelistEntry));
|
||||||
|
|
||||||
FreelistEntry* next = nullptr;
|
|
||||||
for (ssize_t i = cell_count() - 1; i >= 0; i--) {
|
|
||||||
auto* freelist_entry = init_freelist_entry(i);
|
|
||||||
freelist_entry->set_live(false);
|
|
||||||
freelist_entry->next = next;
|
|
||||||
next = freelist_entry;
|
|
||||||
}
|
|
||||||
m_freelist = next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HeapBlock::deallocate(Cell* cell)
|
void HeapBlock::deallocate(Cell* cell)
|
||||||
|
|
|
@ -25,10 +25,12 @@ public:
|
||||||
|
|
||||||
size_t cell_size() const { return m_cell_size; }
|
size_t cell_size() const { return m_cell_size; }
|
||||||
size_t cell_count() const { return (block_size - sizeof(HeapBlock)) / m_cell_size; }
|
size_t cell_count() const { return (block_size - sizeof(HeapBlock)) / m_cell_size; }
|
||||||
bool is_full() const { return !m_freelist; }
|
bool is_full() const { return !has_lazy_freelist() && !m_freelist; }
|
||||||
|
|
||||||
ALWAYS_INLINE Cell* allocate()
|
ALWAYS_INLINE Cell* allocate()
|
||||||
{
|
{
|
||||||
|
if (has_lazy_freelist())
|
||||||
|
return cell(m_next_lazy_freelist_index++);
|
||||||
if (!m_freelist)
|
if (!m_freelist)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
VERIFY(is_valid_cell_pointer(m_freelist));
|
VERIFY(is_valid_cell_pointer(m_freelist));
|
||||||
|
@ -40,7 +42,8 @@ public:
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
void for_each_cell(Callback callback)
|
void for_each_cell(Callback callback)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < cell_count(); ++i)
|
auto end = has_lazy_freelist() ? m_next_lazy_freelist_index : cell_count();
|
||||||
|
for (size_t i = 0; i < end; ++i)
|
||||||
callback(cell(i));
|
callback(cell(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +74,8 @@ public:
|
||||||
private:
|
private:
|
||||||
HeapBlock(Heap&, size_t cell_size);
|
HeapBlock(Heap&, size_t cell_size);
|
||||||
|
|
||||||
|
bool has_lazy_freelist() const { return m_next_lazy_freelist_index < cell_count(); }
|
||||||
|
|
||||||
struct FreelistEntry final : public Cell {
|
struct FreelistEntry final : public Cell {
|
||||||
FreelistEntry* next { nullptr };
|
FreelistEntry* next { nullptr };
|
||||||
|
|
||||||
|
@ -89,6 +94,7 @@ private:
|
||||||
|
|
||||||
Heap& m_heap;
|
Heap& m_heap;
|
||||||
size_t m_cell_size { 0 };
|
size_t m_cell_size { 0 };
|
||||||
|
size_t m_next_lazy_freelist_index { 0 };
|
||||||
FreelistEntry* m_freelist { nullptr };
|
FreelistEntry* m_freelist { nullptr };
|
||||||
alignas(Cell) u8 m_storage[];
|
alignas(Cell) u8 m_storage[];
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue