How the heap stores your allocation

Where the metadata sits, how much space is really used, and how free/delete work from just the pointer p.

⚠ The crux: two different "sizes"

Header offset = a fixed constant hard-coded in the allocator (e.g. 16 bytes). Not stored — the allocator's own code knows it. That's why free(p) can compute p - headerSize from just p.

Block size = how big this allocation is. This is stored, inside the header. free uses the fixed offset to find the header, then reads the block size from it.

1. malloc + free C

HEADERblock size + flags / free-list links
YOUR DATAraw bytes, e.g. malloc(4)
NOT initialized
PADDINGalignment
▲ p − headerSize
(header lives here)
▲ p (malloc returns this)

2. new + delete C++

HEADERblock size + flags / links
YOUR OBJECTconstructor HAS run
e.g. new Entity()
PADDINGalignment
▲ p − headerSize
▲ p (new returns this)

3. new[] + delete[] C++ arrays

HEADERallocator: block size + links
elem[0]ctor ran
elem[1] …ctor ran
PAD
▲ allocator header
▲ p − cookieSize
▲ p (points at elem[0])

Note: for simple types like int[] (no destructor) some compilers skip the count cookie — but for objects with destructors it's always there. Exact header/cookie sizes are allocator- and compiler-specific; the shapes above are the idea, not exact byte counts.

The pairing rule (never cross these)

malloc ↔ free  •  new ↔ delete  •  new[] ↔ delete[]. Crossing them (e.g. free on a new pointer) skips the destructor and can mismatch allocators → corruption / UB.