Linux 内核的内存管理系统是操作系统最复杂的子系统之一,负责高效地管理物理内存和虚拟内存。其主要功能包括:
Linux 支持三种内存模型:
Linux 将物理内存划分为几个区域(zone):
Linux 使用伙伴系统管理物理页面的分配和释放:
struct zone {
...
struct free_area free_area[MAX_ORDER];
...
};
struct free_area {
struct list_head free_list[MIGRATE_TYPES];
unsigned long nr_free;
};
32位系统典型布局:
0x00000000 - 0xC0000000 : 用户空间(3GB)
0xC0000000 - 0xFFFFFFFF : 内核空间(1GB)
64位系统典型布局:
0x0000000000000000 - 0x00007fffffffffff : 用户空间(128TB)
0xffff800000000000 - 0xffffffffffffffff : 内核空间(128TB)
Linux 使用四级页表结构(64位系统): 1. PGD (Page Global Directory) 2. P4D (Page 4th Level Directory) 3. PUD (Page Upper Directory) 4. PMD (Page Middle Directory) 5. PTE (Page Table Entry)
内存映射通过mmap
系统调用实现,有两种主要类型:
- 文件映射:将文件内容映射到进程地址空间
- 匿名映射:分配不与文件关联的内存
基于伙伴系统,提供以下接口:
- alloc_pages
:分配2^n个连续物理页
- __get_free_pages
:分配并返回虚拟地址
- get_zeroed_page
:分配清零的页
用于管理内核中小对象的分配,解决内部碎片问题。有三种实现: 1. SLAB:经典实现 2. SLUB:简化版,现代系统默认 3. SLOB:用于内存受限的系统
struct kmem_cache {
struct array_cache *cpu_cache; // 每CPU缓存
unsigned int size; // 对象大小
unsigned int objsize; // 实际对象大小
unsigned int offset; // 空闲指针偏移
struct kmem_cache_node *node[MAX_NUMNODES]; // 节点缓存
...
};
分配虚拟地址连续但物理地址不一定连续的内存,用于大块内存分配。
Linux 使用页面缓存来缓存文件数据,主要特点: - 使用radix树高效索引 - 采用写回(writeback)策略 - 支持预读(readahead)
当物理内存不足时,将不常用的页面换出到交换空间: - 使用交换区(swap area)存储换出页面 - 每个交换区由多个4K的页槽(page slot)组成 - 使用交换缓存(swap cache)管理换入换出
回收算法基于LRU(最近最少使用)改进,分为: - 活跃链表(active list) - 非活跃链表(inactive list)
自动将普通页(4K)合并为大页(2M),减少TLB失效,提高性能。
在内存回收前尝试压缩页面,减少交换I/O。
支持运行时添加或移除内存模块。
通过cgroups限制和监控进程组的内存使用。
重要/proc/sys/vm参数:
- swappiness
:交换倾向(0-100)
- vfs_cache_pressure
:回收inode/dentry缓存倾向
- dirty_ratio
/dirty_background_ratio
:脏页比例阈值
- min_free_kbytes
:最小保留内存
- zone_reclaim_mode
:内存区域回收策略
Linux 内存管理系统是一个高度优化的复杂子系统,它通过多种机制和算法在以下方面取得平衡: - 性能(减少碎片、提高缓存命中率) - 可靠性(防止内存耗尽) - 灵活性(支持多种硬件架构) - 可扩展性(从小型嵌入式系统到大型服务器)
理解Linux内存管理机制对于系统调优、性能分析和问题诊断至关重要。随着硬件发展和新需求出现,Linux内存管理仍在不断演进,如对非易失性内存(NVM)的支持、更智能的回收算法等。