---
title: "Linux Virtual Memory and Page Tables"
description: "An in-depth technical guide to Linux virtual memory management and page table structures"
keywords: ["linux", "virtual memory", "page tables", "TLB", "huge pages", "OOM killer", "NUMA", "memory cgroups"]
category: "linux"
---

Linux uses a multi-level page table structure to map virtual memory addresses to physical memory frames. The standard configuration is a 4-level page table with a Page Global Directory (PGD), Page Upper Directory (PUD), Page Middle Directory (PMD), and Page Table Entries (PTE). Each level of the hierarchy contains 512 entries that point to the next level, allowing the kernel to efficiently translate 48-bit virtual addresses down to 52-bit physical addresses as of the x86-64 architecture in Linux 5.x.

When a virtual address is accessed, the CPU first checks its Translation Lookaside Buffer (TLB) cache for a mapping. If no mapping is found (a TLB miss), the CPU walks the multi-level page tables in memory to find the physical address, which can take hundreds of CPU cycles. To mitigate TLB misses, the kernel can periodically flush the TLB, either selectively for a single address space or globally across all running processes. Flushing the TLB is an expensive operation that should be minimized.

Huge pages are a Linux feature that maps 2MB or 1GB of contiguous physical memory into a single virtual page, reducing the number of page table entries required and TLB misses. Huge pages are enabled with the CONFIG_TRANSPARENT_HUGEPAGE kernel configuration option and the vm.nr_hugepages sysctl. Transparent Huge Pages (THP) is an extension that automatically manages the allocation and usage of huge pages without requiring manual configuration.

The vm.overcommit_memory sysctl controls how the Linux kernel handles overcommitting of virtual memory. Setting it to 2 enables "always overcommit" mode, where the kernel allows processes to allocate more virtual memory than the system has physical memory. This can lead to out-of-memory (OOM) conditions, which are handled by the OOM killer. The oom_score_adj parameter allows prioritizing which processes the OOM killer should target first.

Non-Uniform Memory Access (NUMA) is a hardware architecture where the latency and bandwidth of memory accesses depends on the physical location of the memory relative to the CPU. The numactl command allows associating processes, memory, and CPUs with specific NUMA nodes to optimize performance. Memory cgroups in Linux v2 provide additional controls to limit, reserve, and account for memory usage by process groups.

Kernel Same-page Merging (KSM) is a Linux feature that scans memory and automatically merges identical pages from different processes into a single shared page, reducing overall memory usage. It is enabled with the CONFIG_KSM kernel configuration option and controlled via the /sys/kernel/mm/ksm/ sysctl interface.The Linux virtual memory subsystem also supports Persistent Memory (PMEM) devices, which are non-volatile memory that can be directly accessed like regular memory. PMEM is exposed to applications through the DAX (Direct Access) mechanism, which maps PMEM directly into the application's address space without the need for a file system. DAX can be enabled on ext4 and XFS file systems using the dax mount option. Applications can then use PMEM through regular load and store instructions, bypassing the page cache for improved performance.

Another advanced virtual memory feature in Linux is Memory Hotplug, which allows adding or removing physical memory modules at runtime without rebooting the system. This is useful for cloud and virtualized environments where memory capacity needs to be dynamically adjusted. Memory Hotplug is enabled with the CONFIG_MEMORY_HOTPLUG kernel configuration and managed through the /sys/devices/system/memory/ sysfs interface.

The Linux kernel also provides control over page table isolation (PTI), also known as KAISER, which is a security feature that separates the kernel's page tables from user space to mitigate side-channel attacks like Meltdown. PTI can be enabled or disabled using the pti kernel command line parameter, and its behavior can be tuned using the kpti_force_enabled and kpti_force_off sysctl options.

Finally, the Linux kernel supports Kernel Address Sanitizer (KASAN), which is a compile-time instrumentation tool that detects out-of-bounds memory accesses, use-after-free bugs, and other memory safety issues in the kernel. KASAN is enabled with the CONFIG_KASAN kernel configuration option and can provide valuable debugging information when investigating complex virtual memory-related issues.Linux also provides advanced control over memory usage through the use of memory cgroups. Memory cgroups, introduced in cgroup v2, allow administrators to set limits, reservations, and other policies on the memory usage of process groups. This includes options to set hard limits, soft limits, and memlocks to prevent pages from being swapped out. Memory cgroups also track detailed usage metrics like active and inactive file/anonymous pages, kernel memory, and swap usage. These controls are exposed through the /sys/fs/cgroup/memory/ interface and can be managed using the systemd-run and systemd-cgls commands.

Another powerful Linux virtual memory feature is Non-Uniform Memory Access (NUMA) awareness and optimization. NUMA systems have multiple memory banks attached to different CPU sockets, leading to varying memory access latencies depending on the physical location of the memory relative to the CPU. The Linux kernel's NUMA awareness allows it to intelligently allocate memory and schedule processes to optimize for the NUMA topology. This is controlled through the numactl command, which can pin processes, memory, and CPUs to specific NUMA nodes. Advanced users can also configure the kernel's page migration and memory balancing policies through sysctl options like kernel.numa_balancing.

The Linux kernel also includes support for Kernel Same-page Merging (KSM), a feature that scans the physical memory of running processes and automatically merges identical pages into a single shared copy. This can significantly reduce the total memory footprint, especially in virtualized environments with many similar guest operating systems. KSM is enabled via the CONFIG_KSM kernel configuration option and controlled through the /sys/kernel/mm/ksm/ sysfs interface, where parameters like scanning frequency and merge thresholds can be adjusted.Linux also provides advanced control over the kernel's handling of out-of-memory (OOM) conditions through the OOM killer subsystem. When the system runs out of available memory, the OOM killer is responsible for selecting and terminating one or more processes to free up memory. The oom_score_adj parameter allows administrators to adjust the "score" of individual processes, which determines their relative likelihood of being killed by the OOM killer. This can be used to protect critical system processes or prioritize less important workloads for termination. The OOM killer's behavior can also be further customized through kernel command line parameters like oom_kill_allocating_task and panic_on_oom.

In addition to the standard 4-level page table hierarchy, Linux also supports Transparent Huge Pages (THP), which can map 2MB or 1GB of contiguous physical memory into a single virtual page. This reduces the number of page table entries required and can significantly improve performance by reducing TLB misses. THP is enabled by default in many Linux distributions and can be controlled through the /sys/kernel/mm/transparent_hugepage/ sysfs interface, where options like defrag, enabled, and khugepaged_scan_sleep_millisecs can be adjusted. THP can be further tuned for specific workloads through the use of madvise system calls or by setting the vm.nr_hugepages sysctl.

Finally, Linux provides a set of advanced memory overcommitment controls through the vm.overcommit_memory sysctl. This parameter determines how the kernel handles situations where processes attempt to allocate more virtual memory than the system has physical memory available. Setting vm.overcommit_memory to 2 enables "always overcommit" mode, which can lead to out-of-memory (OOM) conditions that are handled by the OOM killer. Administrators can fine-tune this behavior by adjusting the vm.overcommit_ratio and vm.overcommit_kbytes parameters, which control the amount of physical memory that can be overcommitted.