For any process that uses glibc, heaps are managed by arenas. Each arena owns one or more heaps, which in turn are subdivided into chunks to facilitate allocating and freeing memory. We can see that the hierarchy is arenas heaps chunks.

To interact with the heap, glibc provides heap manager functions such as malloc(size) (to allocate memory space of a certain size) and free(ptr) (to free memory space allocated by malloc).

Most of the time, the process will allocate and free memory using the (only) heap owned by the main arena, which is created on program start-up; though threads spawn their own heaps as well. Note that since threads share the entire memory space of the process, all heaps are shared.

To handle an allocation request (malloc), the heap manager looks at various places in order:

  • If the requested size is over MMAP_THRESHOLD (512KiB for 32-bit), the heap manager uses mmap to create a chunk and returns it.
  • If there is an existing free chunk that fit size requirements, it is returned.
  • If a larger chunk exist, the heap manager splits a small chunk off of a larger free chunk and returns it.
  • If the top chunk has enough space, a new chunk is allocated and returned.
  • If there’s no space left, the heap manager calls sbrk() to expand the heap and allocate a chunk.

If all of above fails, the system is out of memory and malloc returns NULL accordingly.