<ply-base.h>
namespace ply
Memory

At the lowest level, there's virtual memory, which can be mapped to physical memory using the underlying operating system.

The heap sits directly above that, dividing memory into variable-sized blocks that can be dynamically allocated and freed by the application as needed. Higher-level containers for managing memory, like String, Array, Map, Owned and Reference, are described in later sections.

Heap

Plywood contains its own heap, which lets you allocate and free variable-sized blocks of memory.

Low-level allocation
static voidalloc(uptr num_bytes)
static voidrealloc(void* ptr, uptr num_bytes)
static voidfree(void* ptr)
static voidalloc_aligned(uptr num_bytes, u32 alignment)
Creating and destroying objects
static Tcreate<T>(Args&& args)
static void destroy(T* obj)
Monitoring the heap
static void set_out_of_memory_handler(Functor<void()> handler)
static Heap::Stats get_stats()
static void validate()

The Plywood heap is separate from the C Standard Library's heap. Both heaps can coexist in the same program, but memory allocated from a specific heap must always be freed using the same heap. Plywood's heap implementation uses dlmalloc under the hood.

Heap is thread-safe. All member functions can be called concurrently from separate threads.

Low-level Allocation

static voidalloc(uptr num_bytes)

Allocates a block of memory from the Plywood heap. Equivalent to malloc. Always returns 16-byte aligned memory, suitable for SIMD vectors. Returns nullptr if allocation fails.

static voidrealloc(voidptr,  uptr num_bytes)

Resizes a previously allocated block. The contents are preserved up to the smaller of the old and new sizes. May return a different pointer.

static voidfree(voidptr)

Frees a previously allocated block, returning the memory to the heap.

static voidalloc_aligned(uptr num_bytes,  u32 alignment)

Allocates memory with a specific alignment. Use for alignments greater than 16 bytes.

Creating and Destroying Objects

By default, Plywood will override C++ new and delete to use the Plywood heap. If you don't want this behavior, perhaps because you're integrating Plywood into an existing application, define PLY_OVERRIDE_NEW=0.

You can create and destroy C++ objects in the Plywood heap directly using Heap::create and Heap::destroy, which essentially work like new and delete:

template <typename Type> static Typecreate<Type>(Args&& args)

Allocates heap memory for an object of type Type and calls the constructor. The provided arguments are passed to the constructor using perfect forwarding.

template <typename Type> static void destroy(Typeobj)

Invokes the destructor of an object and frees its memory back to the heap.

Example
Owned<Foo> create_foo() {
    return Heap::create<Foo>();
}

void destroy(Foo* foo) {
    Heap::destroy(foo);
}

Monitoring the Heap

static void set_out_of_memory_handler(Functor<void()> handler)

Sets an out-of-memory handler. handler will be called if an allocation fails due to insufficient system memory.

Out-of-memory events are usually unrecoverable. There's really no ideal way to handle them, other than to collect a report when the event occurs so that the issue can be investigated. In general, developers should establish a memory budget and aim to stay within it.

static Heap::Stats get_stats()

Returns statistics about heap usage. num_bytes_allocated is the sum of the sizes of all allocated blocks. virtual_memory_size, a larger number, is the total amount of system memory used to store those blocks, including bookkeeping overhead and unused space.

{table caption="Heap::Stats members"} uptr|num_bytes_allocated uptr|virtual_memory_size {/table}

static void validate()

Validates the heap's internal consistency. Useful for debugging. Will force an immediate crash if the heap is corrupted, which is usually caused by a memory overrun or dangling pointer. Inserting calls to validate can help track down the cause of the corruption.

VirtualMemory

The VirtualMemory class is a platform-independent wrapper for mapping virtual memory to physical memory.

static VirtualMemory::Info get_page_info()
static bool alloc(void*& out_addr, uptr num_bytes)
static bool reserve(void*& out_addr, uptr num_bytes)
static void commit(void* addr, uptr num_bytes)
static void decommit(void* addr, uptr num_bytes)
static void free(void* addr, uptr num_bytes)

In C++ applications, memory is represented as a 32-bit or 64-bit address space known as virtual memory, which is divided into fixed-sized pages. Most pages are initially unusable and will cause an access violation or segmentation fault if accessed. To make pages usable, they must be mapped to physical memory by the underlying operating system.

static VirtualMemory::Info get_page_info()

Returns information about the system's virtual memory page size and allocation alignment. VirtualMemory::Info has these members:

{table caption="VirtualMemory::Info members"} uptr|alloc_alignment uptr|page_size {/table}

static Stats get_usage_summary()

Returns statistics about the current process's virtual memory usage.

static bool alloc_pages(void*& out_addr,  uptr num_bytes)

Allocates and commits virtual memory pages. The address is written to out_addr. Returns true on success.

static bool reserve_pages(void*& out_addr,  uptr num_bytes)

Reserves virtual address space without committing physical memory. Use commit_pages later to back it with physical memory.

static void commit_pages(voidaddr,  uptr num_bytes)

Commits previously reserved pages, backing them with physical memory.

static void decommit_pages(voidaddr,  uptr num_bytes)

Decommits pages, releasing the physical memory while keeping the address space reserved.

static void free_pages(voidaddr,  uptr num_bytes)

Frees previously allocated or reserved pages, returning the address space to the system.