HeapPageXL
Description
Per-XL-region descriptor. One per allocation >2 KiB. XL allocations are page-aligned standalone mmaps with no bitmap and no sub-slotting; the descriptor’s presence in xl_in_use[] IS the in-use bit, presence in xl_freed[] IS the retained bit. Both arrays are grown by doubling; live / retained lookup is a linear scan over the relevant array.
Fields
| Name | Description |
|---|---|
page |
Base of the user mmap (4 KiB-aligned). |
os_pages |
Mmap size in OS-page units (each unit is HEAP_PAGE_SIZE * HEAP_PAGES_PER_OS_PAGE bytes). Equal to the value passed to the kernel; free unmaps exactly that many bytes. |
Usage example (Cross-references)
Usage examples (Cross-references)
- In
Heap.c:406:
// =============================================================================
static bool heap_xl_array_reserve(HeapAllocator *heap, HeapPageXL **arr, u32 *cap_inout, u32 len) {
if (len < *cap_inout)
return true;- In
Heap.c:410:
return true;
u32 want_cap = *cap_inout ? *cap_inout * 2u : 0u;
size want_bytes = (size)want_cap * sizeof(HeapPageXL);
size new_bytes = os_page_round_up(want_bytes ? want_bytes : sizeof(HeapPageXL));
u32 new_cap = (u32)(new_bytes / sizeof(HeapPageXL));- In
Heap.c:411:
u32 want_cap = *cap_inout ? *cap_inout * 2u : 0u;
size want_bytes = (size)want_cap * sizeof(HeapPageXL);
size new_bytes = os_page_round_up(want_bytes ? want_bytes : sizeof(HeapPageXL));
u32 new_cap = (u32)(new_bytes / sizeof(HeapPageXL));
HeapPageXL *fresh = (HeapPageXL *)os_page_map(&heap->base, new_bytes);- In
Heap.c:412:
size want_bytes = (size)want_cap * sizeof(HeapPageXL);
size new_bytes = os_page_round_up(want_bytes ? want_bytes : sizeof(HeapPageXL));
u32 new_cap = (u32)(new_bytes / sizeof(HeapPageXL));
HeapPageXL *fresh = (HeapPageXL *)os_page_map(&heap->base, new_bytes);
if (!fresh)- In
Heap.c:413:
size new_bytes = os_page_round_up(want_bytes ? want_bytes : sizeof(HeapPageXL));
u32 new_cap = (u32)(new_bytes / sizeof(HeapPageXL));
HeapPageXL *fresh = (HeapPageXL *)os_page_map(&heap->base, new_bytes);
if (!fresh)
return false;- In
Heap.c:417:
return false;
if (*arr && len) {
MemCopy(fresh, *arr, (size)len * sizeof(HeapPageXL));
}
if (*arr) {- In
Heap.c:420:
}
if (*arr) {
os_page_unmap(&heap->base, *arr, os_page_round_up((size)(*cap_inout) * sizeof(HeapPageXL)));
}
*arr = fresh;- In
Heap.c:461:
// already the last) and shrink the length. Order is not preserved --
// fine because both arrays are pure sets of descriptors.
static FORCE_INLINE HeapPageXL heap_xl_in_use_swap_remove(HeapAllocator *heap, u32 idx) {
HeapPageXL out = heap->xl_in_use[idx];
heap->xl_in_use_len -= 1u;- In
Heap.c:462:
// fine because both arrays are pure sets of descriptors.
static FORCE_INLINE HeapPageXL heap_xl_in_use_swap_remove(HeapAllocator *heap, u32 idx) {
HeapPageXL out = heap->xl_in_use[idx];
heap->xl_in_use_len -= 1u;
if (idx != heap->xl_in_use_len) {- In
Heap.c:470:
}
static FORCE_INLINE HeapPageXL heap_xl_freed_swap_remove(HeapAllocator *heap, u32 idx) {
HeapPageXL out = heap->xl_freed[idx];
heap->xl_freed_len -= 1u;- In
Heap.c:471:
static FORCE_INLINE HeapPageXL heap_xl_freed_swap_remove(HeapAllocator *heap, u32 idx) {
HeapPageXL out = heap->xl_freed[idx];
heap->xl_freed_len -= 1u;
if (idx != heap->xl_freed_len) {- In
Heap.c:579:
u64 target = footprint - footprint / 4u; // 75% of current
while (heap->base.footprint_bytes > target && heap->xl_freed_len > 0u) {
HeapPageXL ent = heap_xl_freed_swap_remove(heap, heap->xl_freed_len - 1u);
size bytes = (size)ent.os_pages * HEAP_OS_PAGE_SIZE;
heap->retention_bytes -= (u64)bytes;- In
Heap.c:734:
u32 fr_idx = heap_xl_freed_find_match(heap, (u32)os_pages);
if (fr_idx != HEAP_BUCKET_NONE) {
HeapPageXL ent = heap_xl_freed_swap_remove(heap, fr_idx);
ptr = ent.page;
heap->retention_bytes -= (u64)total;- In
Heap.c:748:
}
HeapPageXL desc = {.page = ptr, .os_pages = (u32)os_pages};
heap->xl_in_use[heap->xl_in_use_len++] = desc;
HEAP_MARK_DIRTY(heap);- In
Heap.c:755:
static void heap_free_xl(HeapAllocator *heap, u32 idx) {
HeapPageXL ent = heap_xl_in_use_swap_remove(heap, idx);
size total = (size)ent.os_pages * HEAP_OS_PAGE_SIZE;
HEAP_MARK_DIRTY(heap);- In
Heap.c:1121:
os_page_unmap(&self->base, self->pages, os_page_round_up((size)self->pages_cap * sizeof(HeapPage)));
if (self->xl_in_use)
os_page_unmap(&self->base, self->xl_in_use, os_page_round_up((size)self->xl_in_use_cap * sizeof(HeapPageXL)));
if (self->xl_freed)
os_page_unmap(&self->base, self->xl_freed, os_page_round_up((size)self->xl_freed_cap * sizeof(HeapPageXL)));- In
Heap.c:1123:
os_page_unmap(&self->base, self->xl_in_use, os_page_round_up((size)self->xl_in_use_cap * sizeof(HeapPageXL)));
if (self->xl_freed)
os_page_unmap(&self->base, self->xl_freed, os_page_round_up((size)self->xl_freed_cap * sizeof(HeapPageXL)));
if (self->recycle)
os_page_unmap(&self->base, self->recycle, os_page_round_up((size)self->recycle_cap * sizeof(void *)));- In
Heap.h:175:
void *page;
u32 os_pages;
} HeapPageXL;
/// HeapAllocator owns:
- In
Heap.h:225:
/// Storage for both arrays is itself page-mapped and grown by
/// doubling.
HeapPageXL *xl_in_use;
u32 xl_in_use_len;
u32 xl_in_use_cap;- In
Heap.h:228:
u32 xl_in_use_len;
u32 xl_in_use_cap;
HeapPageXL *xl_freed;
u32 xl_freed_len;
u32 xl_freed_cap;
Last updated on