Linux
内存管理
子系统

深入探索内核中最核心的组件之一,揭秘内存管理的架构、机制与实现细节

内存管理子系统架构

Linux内存管理子系统是整个内核的核心组件之一,它负责管理计算机系统中最宝贵的资源之一 - 内存

整体架构 System Architecture

Linux内存管理子系统由多个紧密协作的组件构成,包括物理内存管理、虚拟内存管理、页面回收、内存分配器等,它们共同构建了一个高效、灵活的内存管理框架。

核心组件 Key Components

  • 物理内存管理

    包括伙伴系统、每CPU页帧缓存和内存区域

  • 虚拟内存管理

    包括页表机制、TLB管理和地址空间管理

  • 内存回收

    包括页面回收、交换和OOM Killer

  • 内存分配器

    包括Slab/Slub/Slob分配器和kmalloc

物理内存管理 Physical Memory

物理内存管理是Linux内核内存管理的基础,它直接处理硬件上的物理内存。

内存布局 Memory Layout

Zone
ZONE_DMA
低于16MB
ZONE_DMA32
低于4GB
ZONE_NORMAL
直接映射区
ZONE_HIGHMEM
高端内存
ZONE_MOVABLE
可迁移区

Linux内核将物理内存划分为不同的区域(Zone),以满足不同硬件和功能的需求。

伙伴系统 Buddy System

伙伴系统是Linux内核中最重要的物理内存分配机制,负责分配物理页面。其核心思想是将内存分为大小为2的幂次方的连续页块,通过分裂和合并这些页块来满足内存分配需求。

分配 通过分裂满足需求
释放 通过合并减少碎片
struct page *__alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
                                 int preferred_nid, nodemask_t *nodemask)
{
    /* ... */
    page = get_page_from_freelist(gfp_mask, order, ...);
    if (likely(page))
        goto out;
        
    page = __alloc_pages_slowpath(gfp_mask, order, ...);
    /* ... */
}

每CPU页帧缓存 Per-CPU Cache

CPU 0 25 pages
CPU 1 18 pages
CPU 2 32 pages

为了优化频繁的页面分配,Linux内核实现了每CPU页帧缓存,它在每个CPU上缓存一定数量的页面,减少对伙伴系统的访问,提高分配效率。

内存分配器 Memory Allocators

Slab

经典实现,按对象大小划分缓存

Slub

简化设计,优化多核性能

Slob

适用于嵌入式系统的简化版本

void *kmalloc(size_t size, gfp_t flags)
{
    struct kmem_cache *cachep;
    void *ret;
    
    /* 获取适合大小的缓存 */
    cachep = kmalloc_caches[kmalloc_index(size)];
    /* 从缓存分配内存 */
    ret = kmem_cache_alloc_trace(cachep, flags, size);
    return ret;
}

内存分配器在伙伴系统的基础上提供了更细粒度的内存分配,它们通过预分配和复用相似大小的对象来提高内存分配的效率。

虚拟内存管理 Virtual Memory

虚拟内存是现代操作系统的核心特性,它提供了进程间的内存隔离,以及比物理内存更大的地址空间。

页表机制 Page Table Mechanism

typedef struct { unsigned long pte; } pte_t;
typedef struct { unsigned long pmd; } pmd_t;
typedef struct { unsigned long pud; } pud_t;
typedef struct { unsigned long pgd; } pgd_t;

Linux使用多级页表来管理虚拟地址到物理地址的映射。在x86_64架构下,通常使用4级页表:PGD、PUD、PMD和PTE,每一级页表通过索引定位到下一级表。

TLB管理 TLB Management

TLB
static inline void flush_tlb_single(unsigned long addr)
{
    /* 刷新单个TLB条目 */
    __asm__ __volatile__("invlpg (%0)" ::"r" (addr) : "memory");
}

翻译后备缓冲区(TLB)是CPU中的一个硬件缓存,用于加速虚拟地址到物理地址的转换过程。当页表发生变化时,内核需要刷新TLB。

地址空间管理 Address Space Management

struct mm_struct {
    struct vm_area_struct *mmap;        /* 虚拟内存区域链表 */
    struct rb_root mm_rb;               /* 虚拟内存区域红黑树 */
    pgd_t * pgd;                        /* 页全局目录 */
    atomic_t mm_users;                  /* 用户计数 */
    atomic_t mm_count;                  /* 引用计数 */
    /* ... */
};
struct vm_area_struct {
    unsigned long vm_start;      /* 开始地址 */
    unsigned long vm_end;        /* 结束地址 */
    struct vm_area_struct *vm_next;  /* 链表下一个VMA */
    struct rb_node vm_rb;       /* 红黑树节点 */
    
    pgprot_t vm_page_prot;      /* 访问权限 */
    unsigned long vm_flags;      /* 标志 */
    
    struct mm_struct *vm_mm;     /* 所属mm_struct */
    /* ... */
};

高级特性 Advanced Features

Linux内存管理子系统包含许多高级特性,用于提高性能和资源利用率。

页面回收 Page Reclamation

LRU算法

维护活跃和不活跃页面列表

页面回写

将脏页写回磁盘

OOM Killer

内存严重不足时终止进程

大页 Huge Pages

2 MB
标准页
4KB
中等大页
2MB
超大页
1GB

大页通过减少页表项数量,提高TLB命中率,显著提升内存密集型应用程序的性能。

NUMA管理 NUMA Management

在NUMA(非统一内存访问)架构上,Linux内核考虑内存访问的局部性,尽量让进程使用与其运行CPU相近的内存节点,减少跨节点访问带来的延迟。

int do_migrate_pages(struct mm_struct *mm, 
                const nodemask_t *from,
                const nodemask_t *to, int flags)
{
    /* 在NUMA节点之间迁移页面 */
}

内存管理系统调用 System Calls

mmap

创建内存映射,将文件或设备映射到进程地址空间。

brk

调整进程的堆空间,用于动态内存分配。

mlock

锁定进程地址空间中的页面,防止其被交换出内存。

madvise

向内核提供关于内存区域使用模式的建议。

内存管理相关系统调用代码示例:

SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
                unsigned long, prot, unsigned long, flags,
                unsigned long, fd, unsigned long, off)
{
    /* ... */
    return ksys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
    /* ... */
}

总结 Summary

Linux内存管理子系统是一个复杂而精密的机制,通过多层次的抽象和优化,高效地管理系统内存资源。它的设计要点包括:

  • 1

    物理内存管理:伙伴系统提供了高效的页面分配

  • 2

    内存分配器:Slab/Slub/Slob提供了细粒度的内存分配

  • 3

    虚拟内存管理:多级页表和TLB优化了地址转换

  • 4

    页面回收:LRU算法和OOM Killer保证了内存紧张时的系统稳定性

  • 5

    高级特性:大页和NUMA支持提供了针对特定场景的性能优化

通过深入理解内存管理子系统的源码实现,我们可以更好地优化系统性能,开发高效的应用程序和内核模块。

探索Linux内存管理源码