Linux Kernel Memory Management Explained: Buddy Allocator, SLUB, kmalloc, and vmalloc

Introduction

In Linux, many processes and the kernel run concurrently while efficiently sharing a limited amount of physical memory (RAM).

Physical memory, however, is not managed simply by using whatever space happens to be free. The Linux kernel manages physical memory in page-sized units, classifies it according to purpose, and uses several mechanisms to allocate and release it quickly.

For example, understanding Linux kernel memory management helps answer questions such as:

  • How does the Linux kernel manage physical memory?
  • How does the Buddy Allocator allocate memory?
  • Why does the Slab Allocator exist?
  • When should kmalloc() and vmalloc() be used?

In production systems, administrators may also inspect /proc/buddyinfo, /proc/slabinfo, /proc/zoneinfo, and slabtop when investigating memory shortages or abnormal kernel memory usage. To interpret this information correctly, it is important to understand how memory is managed inside the kernel.

This article first presents an overview of physical memory management in the Linux kernel and then clearly explains page frames, memory zones, the Buddy Allocator, and the Slab Allocator.

What Is Linux Kernel Memory Management?

In Linux, each process is assigned its own independent virtual address space. The memory used by a process, however, is ultimately part of the physical memory (RAM) managed by the Linux kernel.

For example, when an application allocates memory with malloc() or new, usable memory is reserved in its virtual address space. Behind the scenes, the Linux kernel manages physical memory and allocates pages as needed.

Applications therefore do not manipulate physical memory directly. The Linux kernel acts as an intermediary, managing allocation, release, and reuse so that many processes can use memory safely and efficiently.

The following diagram illustrates the overall structure of memory management in Linux.

The Linux kernel manages all physical memory in fixed-size units called pages, typically 4 KB. It combines several mechanisms based on purpose and allocation size to provide fast, efficient memory management.

  • Page frame: Manages physical memory in page-sized units.
  • Memory zone: Classifies physical memory according to purpose.
  • Buddy Allocator: Allocates and releases physical memory in page-sized units.
  • Slab Allocator (SLUB): Efficiently manages kernel objects.

Each mechanism has a different role, but together they provide fast and efficient memory management. The following sections examine each one in detail.

What Is a Page Frame?

The Linux kernel divides all physical memory (RAM) into fixed-size units called pages. On a typical x86_64 system, one page is 4 KB.

Even when allocating a 16 KB memory region, the kernel allocates pages in 4 KB units rather than individual bytes. The 16 KB region is therefore managed as four pages.

Managing physical memory in pages makes allocation and release efficient and simplifies mapping between physical and virtual memory.

The following diagram illustrates physical memory.

The Linux kernel manages each page in physical memory as a page frame. Strictly speaking, “page” is a general term for a fixed-size unit of memory, while “page frame” refers specifically to a page that exists in physical memory.

For example, when a process allocates memory with malloc(), the kernel assigns free page frames, and the MMU maps those page frames to virtual addresses. The process uses virtual addresses, while the page frames hold the actual data behind the scenes.

For each page frame, the Linux kernel tracks information such as:

  • Whether it is in use or free
  • Which process is using it
  • Whether it is used as page cache
  • Whether it is a dirty page (*)
  • Its reference count

This information is managed internally by a data structure called struct page.

* A dirty page is a page that has been modified in memory but has not yet been written back to disk. The Linux kernel writes it to disk after a certain period or when memory is scarce; this is called writeback.

struct page

In the Linux kernel, every page frame has one corresponding struct page.

A struct page does not store the data contained in the page frame itself. Instead, it stores the page frame’s state and management metadata. It is a kernel-maintained management structure—not the physical page itself—and one instance tracks each page frame.

The following diagram illustrates the relationship.

The Buddy Allocator refers to this struct page information to determine which page frames are free and which can be allocated. Page frames are therefore the most fundamental management unit in Linux kernel memory management.

Memory Zones

The Linux kernel manages physical memory in page-sized units, but not every page can be used for the same purpose.

Some devices, for example, can access only low physical-memory addresses, and some regions may need to be reserved for priority kernel use. The kernel therefore divides physical memory into several regions according to purpose. These classifications are called memory zones.

The following diagram illustrates memory zones. The kernel tracks the zone to which every page frame belongs and allocates pages from the appropriate zone for each use.

Memory ZonePrimary Purpose
DMALow memory for DMA-capable devices
DMA32Memory for 32-bit DMA devices
NormalMemory used by the kernel and ordinary applications
HighMem
High memory used in 32-bit environments (normally unused in 64-bit environments)

DMA Zone

DMA (Direct Memory Access) allows a device to access physical memory directly without involving the CPU. Some older devices cannot access all physical memory and can use only low-address memory. Linux therefore reserves a low-memory region for DMA and manages it as the DMA zone.

The DMA zone rarely requires attention on modern 64-bit servers, but it remains for compatibility.

DMA32 Zone

The DMA32 zone is a memory region for DMA devices that can handle only 32-bit addresses. Some PCI devices, for example, cannot access physical addresses above 4 GB. Physical memory below 4 GB is therefore managed as the DMA32 zone for such devices.

Ordinary applications rarely need to be aware of this zone.

Normal Zone

The Normal zone is the memory region used most frequently by the Linux kernel. Many allocations—including kernel objects, page cache, and various buffers—come from this zone.

Accordingly, the Buddy Allocator normally allocates pages from the Normal zone. In a 64-bit environment, it is effectively the primary physical-memory region.

HighMem Zone

HighMem is a special memory region used by 32-bit Linux. In a 32-bit environment, the amount of physical memory the kernel can access directly is limited, and memory beyond that limit is managed as HighMem.

Using HighMem requires temporarily mapping it into the kernel’s virtual address space, making access more expensive than access to the Normal zone.

By contrast, 64-bit Linux has a vast virtual address space and is not subject to this limitation. HighMem is therefore not normally used in modern 64-bit environments.

Memory Zone Summary

Most production servers today run 64-bit Linux. In practice, the principal memory zone is therefore the Normal zone. DMA and DMA32 exist for compatibility with certain hardware, while HighMem is generally unused in 64-bit environments.

By classifying physical memory according to purpose, the Linux kernel can manage it efficiently while accommodating hardware constraints. The next section explains how page frames within these zones are allocated and released through the Buddy Allocator.

Buddy Allocator

The Buddy Allocator is the memory allocator the Linux kernel uses to efficiently allocate and release physical memory (page frames).

As explained above, the kernel manages physical memory in pages. Managing pages only one at a time, however, would make it difficult to allocate large regions efficiently or reuse released memory.

Linux therefore uses the Buddy Allocator to manage pages in power-of-two units. With a 4 KB base page size, memory is organized into the sizes shown below.

For example, a 16 KB request is satisfied by an order-2 page block containing four 4 KB pages. Managing pages in groups makes it possible to handle memory requests of different sizes flexibly.

How the Buddy Allocator Works

The Buddy Allocator manages physical memory as blocks whose sizes, called orders, are powers of two.

When memory is requested, it first looks for the smallest block that can satisfy the request. If no free block of that size exists, it obtains a larger block and repeatedly splits it until the required size is reached.

For example, if 16 KB is needed but only a 64 KB (order-4) block is free, the allocator first splits it into 32 KB (order-3) blocks and then splits one again into 16 KB (order-2) blocks. One resulting 16 KB block is allocated to the requester, while the remaining blocks stay free.

When memory is released, the allocator checks whether its same-sized “buddy” block is also free. If so, the two blocks are merged into a larger block. This process can repeat, combining blocks successively into 32 KB, 64 KB, and larger units.

In this way, the Buddy Allocator splits blocks to the required size during allocation and merges buddies during release, efficiently managing physical memory while reducing fragmentation.

Slab Allocator (SLUB)

The preceding section explained how the Buddy Allocator manages physical memory in page-sized units. The data handled by the Linux kernel, however, is not always a multiple of 4 KB.

Many kernel objects are only tens or hundreds of bytes in size, including task_struct for process management, inode for file information, dentry for directory entries, and sk_buff for network communication.

If the kernel obtained an entire 4 KB page from the Buddy Allocator whenever it allocated one of these small objects, most of each page would remain unused and a great deal of memory would be wasted.

The kernel therefore uses the Slab Allocator to manage small objects efficiently. Modern Linux uses the improved SLUB Allocator as its standard implementation. This article uses the general term “Slab Allocator” while assuming that the actual implementation is SLUB.

Difference from the Buddy Allocator

Buddy AllocatorSlab Allocator (SLUB)
Manages memory in page-sized units (4 KB or more)Manages small kernel objects
Allocates and releases page framesEfficiently reuses objects
Splits and merges pagesAllocates quickly from caches

The Buddy Allocator manages physical memory in pages. The Slab Allocator uses pages obtained from the Buddy Allocator to manage small objects efficiently. The two mechanisms do not compete; they cooperate while performing different roles.

How the Slab Allocator Works

The Slab Allocator obtains pages from the Buddy Allocator and divides them into objects of the same type and size. To manage task_struct objects, for example, it divides an acquired page into slots for multiple task_struct instances.

Placing multiple objects in one page avoids wasting memory.

* task_struct is the data structure the Linux kernel uses to manage a process.

Whenever a process starts in Linux, one corresponding task_struct is created. This structure contains the information required to manage that process.

Reusing Objects

A major feature of the Slab Allocator is that it reuses previously allocated objects. Reusing objects instead of obtaining a new page from the Buddy Allocator every time makes memory allocation much faster.

A Cache for Each Object Type

The Slab Allocator maintains a dedicated cache, called a Slab Cache, for each type of object. Representative caches include:

Slab CachePurpose
task_structStores process-management information
inodeManages file and directory information
dentryManages directory entries (pathnames)
sk_buffManages network packets
kmalloc-64General-purpose allocations of approximately 64 bytes
kmalloc-128General-purpose allocations of approximately 128 bytes
kmalloc-512General-purpose allocations of approximately 512 bytes

Objects of the same type are allocated from the same cache, allowing initialized objects to be reused efficiently.

kmalloc() and vmalloc()

The Linux kernel provides kmalloc() and vmalloc() as two primary functions for dynamic memory allocation. Both allocate kernel memory, but they differ in allocation method and intended use.

kmalloc()

kmalloc() allocates memory that is physically contiguous. To allocate 128 bytes, for example:

void *buf = kmalloc(128, GFP_KERNEL);

When kmalloc() is called, it first searches the SLUB Allocator’s cache for a free object. If one is available, it returns that object. Otherwise, it obtains a new page from the Buddy Allocator, adds it to the SLUB cache, and then allocates memory from it.

Thus, kmalloc() operates through cooperation between the Buddy Allocator and the SLUB Allocator.

Memory allocated by kmalloc() is contiguous in both virtual and physical address space. It is therefore used when physical contiguity is required, such as in certain device-driver operations involving DMA (Direct Memory Access).

vmalloc()

vmalloc() allocates a contiguous region in virtual address space. For example:

void *buf = vmalloc(1024 * 1024);

The physical memory used by vmalloc() does not need to be contiguous. It may, for example, use widely separated physical pages:

Page 5
Page 18
Page 102
Page 230

By mapping these pages into a contiguous virtual address range through page tables, the kernel can use them as if they were contiguous. This makes large memory regions easier to allocate. Access has slightly more overhead than kmalloc(), however, because it goes through page-table mappings.

Differences Between kmalloc() and vmalloc()

Itemkmalloc()vmalloc()
Virtual addressesContiguousContiguous
Physical addressesContiguousMay be noncontiguous
Internal mechanismSLUB + Buddy AllocatorAllocates pages and maps them through page tables
Primary useFast, small-to-medium allocationsLarge memory regions
Typical examplesInternal kernel operations, device drivers, and networkingLarge buffers and kernel modules
Relationship to DMAUsed for operations requiring physically contiguous memory (* DMA buffers normally use the DMA API)Unsuitable for DMA
Access speedFastSlightly slower because page tables are involved
AdvantageFast accessEasier to allocate large regions
DisadvantageDifficult to obtain large contiguous regionsMore overhead than kmalloc()

Memory Allocation Flow

So far, we have covered the components of Linux kernel memory management. This section brings them together by tracing the allocation of 128 bytes with kmalloc().

1. kmalloc() Is Called

The kernel or a device driver calls kmalloc() to allocate memory dynamically. A 128-byte allocation is written as follows:

void *buf = kmalloc(128, GFP_KERNEL);

The call starts the SLUB Allocator’s memory-allocation process.

2. The SLUB Allocator Checks the Slab Cache

The SLUB Allocator first checks the corresponding Slab Cache. In this example, that is the kmalloc-128 cache. If the cache contains a free object, it returns the object immediately and allocation is complete.

3. If No Object Is Free, It Requests Memory from the Buddy Allocator

If the Slab Cache has no free object, a new page is required. The SLUB Allocator asks the Buddy Allocator to allocate one.

4. The Buddy Allocator Allocates a Page

The Buddy Allocator searches for free pages in a memory zone. It looks for a block of the order required by the request. If none exists, it splits a larger page block to create one, then returns the acquired page to the SLUB Allocator.

5. The SLUB Allocator Divides the Page

The page returned by the Buddy Allocator is not used as-is. The SLUB Allocator divides it into equal-sized objects and registers them with the Slab Cache. A cache for 128-byte objects, for example, places multiple 128-byte objects in one page. One free object is then returned to the caller.

6. Objects Are Reused

When the allocated object is no longer needed, it is returned to the SLUB Allocator. At this point, the page itself is not returned to the Buddy Allocator. Only the object returns to the Slab Cache, where it can be reused by a later allocation.

Consequently, most allocations can be handled quickly without accessing the Buddy Allocator. When every object in a page is no longer needed, the SLUB Allocator returns that page to the Buddy Allocator. The Buddy Allocator merges free buddies as appropriate so the memory can be reused as a larger page block.

What to Check During Troubleshooting

Linux exposes various kernel memory-management statistics under /proc. When investigating issues such as exhausted physical memory, kernel memory leaks, or page-allocation failures, examining Buddy Allocator and SLUB Allocator usage may help identify the cause.

Checking Buddy Allocator Usage

The number of free pages available to the Buddy Allocator can be checked in /proc/buddyinfo.

[root@almalinux ~]# cat /proc/buddyinfo
Node 0, zone      DMA      2      1      2      3      2      1      2      1      1      0      3
Node 0, zone    DMA32   4076   3308   2707   1819   1355    842    501    293    131      6    241
Node 0, zone   Normal   1777   2289   7028   3472   1095    146     31     12      3      0      0
[root@almalinux ~]#

This file shows the number of free blocks at each order in every memory zone. If very few high-order blocks—that is, large contiguous page blocks—are free, memory may be heavily fragmented.

Checking SLUB Allocator Usage

SLUB Allocator usage can be checked with the slabtop command.

[root@almalinux ~]# slabtop -o
 Active / Total Objects (% used)    : 257260 / 283100 (90.9%)
 Active / Total Slabs (% used)      : 8675 / 8675 (100.0%)
 Active / Total Caches (% used)     : 164 / 232 (70.7%)
 Active / Total Size (% used)       : 55745.31K / 61446.80K (90.7%)
 Minimum / Average / Maximum Object : 0.01K / 0.22K / 8.00K

  OBJS ACTIVE  USE OBJ SIZE  SLABS OBJ/SLAB CACHE SIZE NAME
 39921  39856  99%    0.19K   1901       21      7604K kmalloc-192
 23296  16267  69%    0.03K    182      128       728K lsm_inode_cache
 22272  22131  99%    0.12K    696       32      2784K kernfs_node_cache
 19299  16426  85%    0.19K    919       21      3676K dentry
 14484  13927  96%    0.04K    142      102       568K vma_lock
 14220  13717  96%    0.21K    790       18      3160K vm_area_struct
 13440  12909  96%    0.66K    560       24      8960K inode_cache
  9906   9784  98%    0.10K    254       39      1016K buffer_head
  8576   8199  95%    0.06K    134       64       536K anon_vma_chain
  7392   7073  95%    0.07K    132       56       528K vmap_area

As shown above, it displays the usage and object count of each Slab Cache. Representative caches include:

• dentry
• inode_cache
• vm_area_struct
• kmalloc-192

If one particular cache continues to grow abnormally, it may be a clue pointing to a kernel memory leak.

Checking Slab Cache Details

Detailed information about each Slab Cache is available in /proc/slabinfo.

[root@almalinux ~]# cat /proc/slabinfo
slabinfo - version: 2.1
# name            <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
nf_conntrack_expect      0      0    232   17    1 : tunables    0    0    0 : slabdata      0      0      0
nf_conntrack         208    208    256   16    1 : tunables    0    0    0 : slabdata     13     13      0
nf-frags               0      0    200   20    1 : tunables    0    0    0 : slabdata      0      0      0
fuse_request           0      0    152   26    1 : tunables    0    0    0 : slabdata      0      0      0
fuse_inode             0      0    896   18    4 : tunables    0    0    0 : slabdata      0      0      0
ext4_groupinfo_4k   1628   1628    184   22    1 : tunables    0    0    0 : slabdata     74     74      0
ext4_fc_dentry_update      0      0    104   39    1 : tunables    0    0    0 : slabdata      0      0      0
ext4_inode_cache     818   2314   1216   26    8 : tunables    0    0    0 : slabdata     89     89      0
ext4_free_data       803   1095     56   73    1 : tunables    0    0    0 : slabdata     15     15      0
ext4_allocation_context    120    120    136   30    1 : tunables    0    0    0 : slabdata      4      4      0
ext4_prealloc_space    144    144    112   36    1 : tunables    0    0    0 : slabdata      4      4      0
ext4_system_zone     306    306     40  102    1 : tunables    0    0    0 : slabdata      3      3      0
ext4_io_end_vec     1024   1536     32  128    1 : tunables    0    0    0 : slabdata     12     12      0

/proc/slabinfo provides the following information:

  • Cache name
  • Number of objects
  • Object size
  • Numbers of active and free objects

Use it when you need more detailed information than slabtop provides.

Key Troubleshooting Checks

ItemPrimary CommandWhat to Look For
Buddy Allocatorcat /proc/buddyinfoA shortage of free high-order blocks
Slab Cache usageslabtopAbnormal growth in a particular cache
Slab Cache detailscat /proc/slabinfoAbnormal object counts or sizes

Examining this information together helps identify not only physical-memory exhaustion but also more specific causes such as fragmentation and kernel memory leaks.

Summary

The Linux kernel combines several mechanisms to manage limited physical memory (RAM) efficiently. This article presented an overview of Linux kernel memory management and explained the roles of page frames, memory zones, the Buddy Allocator, the Slab Allocator (SLUB), kmalloc(), and vmalloc().

MechanismRole
Page frameManages physical memory in page-sized units
Memory zoneClassifies physical memory according to purpose
Buddy AllocatorAllocates and releases memory in page-sized units
Slab Allocator (SLUB)Efficiently manages and reuses small kernel objects
kmalloc()Quickly allocates small-to-medium regions of contiguous physical memory
vmalloc()Allocates large regions of virtual memory

During troubleshooting, checking /proc/buddyinfo, slabtop, and /proc/slabinfo can reveal physical-memory fragmentation, SLUB cache usage, and signs of kernel memory leaks. Understanding the purpose of these tools makes memory-related problems easier to investigate efficiently.

If you’d like to learn more about Linux memory management, I’ve covered the topic in detail in the following book. Please check it out if you’re interested.

Linux Memory Management Explained

Learn How Linux Works Through Visual Explanations

This book explains how Linux memory management works through clear, visual illustrations, making the concepts easy to understand even for beginners.


View the Book on Kindle

コメント