跳转至

内存是如何分配的

在 Linux 中,内存管理是由 内存管理子系统(Memory Management Subsystem) 负责的,涉及多个层次的分配机制,包括 物理内存管理、虚拟内存管理、页管理、缓存管理 等。下面是 Linux 内存分配的主要机制:


1. 物理内存管理

Linux 物理内存管理基于 分页(Paging) 机制,而不是分段(Segmentation)。主要机制包括:

1.1 页(Page)和页帧(Page Frame)

  • Linux 默认使用 4KB 页(也支持大页,如 HugePages)。
  • 物理内存被划分为固定大小的页帧(Page Frame),每个页帧通常是 4KB。
  • 页帧由 伙伴系统(Buddy System) 进行管理。

1.2 伙伴系统(Buddy System)

  • 伙伴系统用于管理 连续的空闲内存块,提高分配和合并效率。
  • 它将物理内存分成 2^n 大小的块,并尽可能合并相邻的空闲块,以减少内存碎片。

2. 虚拟内存管理

Linux 采用 虚拟地址到物理地址映射(VA → PA),并使用 页表(Page Table) 来管理虚拟地址。

2.1 地址空间

  • 用户态地址空间(User Space):通常是 0x0000000000000000 - 0x00007FFFFFFFFFFF(48-bit)。
  • 内核态地址空间(Kernel Space):通常是 0xFFFF800000000000 - 0xFFFFFFFFFFFFFFFF(高地址)。

2.2 页表(Page Table)

Linux 采用 多级页表(4 级/5 级) 来减少内存开销: - PGD(Page Global Directory) - PUD(Page Upper Directory) - PMD(Page Middle Directory) - PTE(Page Table Entry)

映射关系:虚拟地址 → 物理地址


3. 内存分配机制

3.1 用户态内存分配

3.1.1 malloc() & brk()/mmap()

  • malloc() 申请内存时,可能调用 brk()mmap()
  • brk():扩展 堆(Heap)
  • mmap():映射大块内存到虚拟地址空间(用于大内存分配)。

3.1.2 进程堆栈

  • 栈(Stack):自动管理,函数调用时分配局部变量,递归深度受栈大小限制。
  • 堆(Heap):由 malloc() 申请,由 free() 释放。

3.2 内核态内存分配

3.2.1 kmalloc()

  • 内核的 malloc(),用于分配小块物理内存(通常小于 PAGE_SIZE)。
  • 使用 Slab 分配器 进行管理(减少碎片)。

3.2.2 vmalloc()

  • 分配 连续的虚拟内存(但可能是物理上不连续)。
  • 用于分配大块内存(超过 PAGE_SIZE)。

3.2.3 alloc_pages()

  • 直接调用 伙伴系统 分配 2^n 个页。
  • 适用于驱动或 DMA 设备的物理页分配。

4. 内存回收

Linux 使用 页回收(Page Reclaim)交换(Swap) 机制来优化内存使用:

4.1 页回收(Page Reclaim)

  • 通过 LRU(Least Recently Used) 机制回收不常使用的页
  • 可回收的页:
  • 文件页(File-backed Pages):可以丢弃,因为可从磁盘重新加载。
  • 匿名页(Anonymous Pages):只能写入 Swap 才能回收。

4.2 交换(Swap)

  • 当物理内存不足时,Linux 会将匿名页移到 Swap 分区或 Swap 文件中。
  • Swap 机制有:
  • swappiness(控制 Swap 频率,0 表示尽量不用 Swap,100 表示积极使用 Swap)。
  • OOM Killer(当 Swap 也不足时,Linux 可能会杀掉进程)。

5. 常见的内存管理工具

  • free -h:查看内存使用情况(包括 Swap)。
  • top / htop:监控进程的内存占用。
  • vmstat:显示内存分配、Swap 统计等信息。
  • slabtop:查看 Slab 分配器的使用情况。
  • numactl --hardware:查看 NUMA 结构的内存分布。

6. 总结

机制 作用
伙伴系统 管理物理页帧,减少碎片
Slab 分配器 管理小块内存,提高缓存效率
页表管理 实现虚拟地址到物理地址映射
LRU 回收 回收不常用的内存页
Swap 交换不活跃的匿名页到磁盘