A modern operating system manages physical memory as page frames. A page frame can be allocated to a user process or for the kernel to use for its own purposes, such as to allocate its own data structures.
A kernel data object (e.g. a structure representing an "open file" or something) is typically less than the size of a page. So it makes sense to have a two-level allocation hierarchy: one to manage page frames, and one to allocate data structures inside allocated page frames.
Linux uses a buddy allocator to allocate page frames, and a slab allocator to allocate kernel data structures. When the slab allocator needs more memory, it obtains it from the buddy allocator.
This approach works well for Linux, since it supports different page sizes; x86-64 CPUs support 4kB, 2M, and sometimes 2GB pages, and a binary buddy allocator can support this with very little modification.
Windows NT, by comparison, uses a simple free list to implement page frame allocation. Actually, that's not quite accurate; it uses multiple free lists to implement cache colouring, but that's a story for another time. Again, it layers another allocator on top to handle kernel data structures.
It's a similar story with Mach, the microkernel underneath macOS and iOS. Kernel data structures are implemented with a zone allocator, which plays the same role as the slab allocator in Linux. It, again, operates as a layer above the physical page frame allocator.