6. Memory Management
HAProxy uses a simple and fast pool-based memory management. Since it relies on a small number of different object types, it’s much more efficient to pick new objects from a pool which already contains objects of the appropriate size than to call malloc() for each different size. The pools are organized as a stack or LIFO, so that newly allocated objects are taken from recently released objects still hot in the CPU caches. Pools of similar sizes are merged together, in order to limit memory fragmentation.
By default, since the focus is set on performance, each released object is put back into the pool it came from, and allocated objects are never freed since they are expected to be reused very soon.
On the CLI, it is possible to check how memory is being used in pools thanks to the “show pools” command:
The pool name is only indicative, it’s the name of the first object type using this pool. The size in parenthesis is the object size for objects in this pool. Object sizes are always rounded up to the closest multiple of 16 bytes. The number of objects currently allocated and the equivalent number of bytes is reported so that it is easy to know which pool is responsible for the highest memory usage. The number of objects currently in use is reported as well in the “used” field. The difference between “allocated” and “used” corresponds to the objects that have been freed and are available for immediate use. The address at the end of the line is the pool’s address, and the following number is the pool index when it exists, or is reported as -1 if no index was assigned.
It is possible to limit the amount of memory allocated per process using the “-m” command line option, followed by a number of megabytes. It covers all of the process’s addressable space, so that includes memory used by some libraries as well as the stack, but it is a reliable limit when building a resource constrained system. It works the same way as “ulimit -v” on systems which have it, or “ulimit -d” for the other ones.
If a memory allocation fails due to the memory limit being reached or because the system doesn’t have any enough memory, then haproxy will first start to free all available objects from all pools before attempting to allocate memory again. This mechanism of releasing unused memory can be triggered by sending the signal SIGQUIT to the haproxy process.
During a reload operation, the process switched to the graceful stop state also automatically performs some flushes after releasing any connection so that all possible memory is released to save it for the new process.