深入理解Linux内核之内存管理

以为是挺重要的一章,虽然有硬件部分,但抽象出来之后提供的API是软件开发常用的基础API,做笔记可以让我读的更细,详细了解一下,也许以后用到了呢。

Linux有一部分固定内存分配给内核,这部分属于保留内存,其余的内存被分为两类,连续内存和非连续内存,两种内存分配算法不同。“页框管理”和“内存管理”描述两种处理连续内存的不同技术,“非连续内存区管理”介绍了非连续内存的第三种技术。

页框管理

Linux在不同的架构上统一采用4KB页框大小作为标准的内存分配单元

页描述符

内核必须记录每个页框当前的状态,例如需要区分哪些页框属于用户进程,哪些页框属于内核代码或者数据;还要区分哪些是空闲等…

页框的状态信息保存在一个类型为page的页描述符中,所有的页描述符都存放在mem_map数组中,每个页描述符长32字节,一个页框有4kb,页描述符总共占千分之7的内存空间。virt_to_page(addr)产生现行地址对应的页描述符地址,pfn_to_page(pfn)宏产生与页框号pfn对应的页描述符地址。页描述符字段:

  • atomic_t _count页的引用计数器,如果为-1则相应页空闲。字段若大于等于0则说明页框被分配给了一个或多个进程。
  • unsigned long flags包含32个页框状态的标志。

非一致内存访问(NUMA)

习惯上认为计算机的内存是均匀、共享的资源,通常期望任何CPU访问访问任何内存所需要的时间都是相同的,但这个假设在某些体系结构上并不成立。这种架构Linux也有支持,给定CPU对不同的内存单元访问时间可能不同。系统物理内存被划分为几个节点。在一个独立的节点内,任一给定CPU访问页面所需要的时间都是相同的,然而不同CPU这个时间可能就不同。对每个CPU而言,内核都试图把耗时节点的访问次数减到最少,这就要小心地选择CPU最常引用的内核数据结构的存放位置。

每个结点又被划分为多个管理区,在下一节介绍。而每个节点都有一个类型为pg_data_t的描述符。

在80X86这个一致性架构中节点的概念没有作用,但为了可移植性内核在所有体系中都会对内存划分节点。在80X86系统中,Linux将所有的内存划进一个节点。

内存管理区(Zone)

在理想的计算机体系架构中,一个页框就是一个内存存储单元,可以用于任何事情,但是实际上有硬件的制约,限制了页框的使用方式,有其实80X86体系的两种硬件约束:

  • ISA总线直接内存存取(DMA)处理器有一个严格的限制:只能对RAM的前16MB寻址。
  • 在具有大容量RAM的现代32位计算机中,CPU不能直接访问所有的物理内存,因为线性地址空间太小。

为了应对这两个限制,Linux 2.6把每个内存节点的物理内存划分为三个管理区(Zone)。在80X86UMA体系结构中的管理区为:

  • ZONE_DMA
    包含低于16MB的内存页框
  • ZONE_NORMAL
    包含高于16MB且低于896MB的内存页框
  • ZONE_HIGHMEN
    包含高于896MB的内存页框

ZONE_DMA和ZONE_NORMAL区包含内存的“常规”页框,通过把它们的线性地址映射到线性地址空间的第4个GB,内核就可以直接访问。每个内存管理区也都有自己的描述符,每个页描述符都有到内存节点和内存管理区的链接。

当内核调用一个内存分配函数时,必须指明请求页框所在的管理区。

为什么ZONE_NORMAL是896以下呢,因为这里说的是固定的内存分配,高4G是分配固定给内核的,而高4G中低128MBLinux未使用,所以还剩下896MB可以使用。ZONE_HIGHMEN的内存是用于分配给第1~3G的线性地址的。

保留的页框池

内核会保留一部分页框给一些原子内存分配请求,只有在内存不足时才会被使用。保留内存的数量(以KB为单位)存放在min_free_kbytes变量中,管理员可以通过向/proc/sys/vm/min_free_kbytes文件修改大小。

分区页框分配器

这个内核子系统处理对连续页框组的内存分配请求,其结构是,“管理区分配器”接受动态内存分配与释放的请求,其下有三个内存管理区,每个管理区拥有CPU页框高速缓存和伙伴系统。

当接受分配请求时,“管理区分配区”寻找一个能满足所请求的一组连续页框内存管理区,在每个管理区内,页框被“伙伴系统”来处理,为达到更好的系统性能,一小部分页框保留在告诉缓存中用于快速的满足对单个页框的分配请求。

分配内存的API中为什么会有获取分配页框地址的接口呢,因为HIGHMEN区域的地址无法在内核态被映射在内存中。

高端内存页框的内核映射

与直接映射的物理内存末端、高端内存的始端所对应的线性地址存放在hight_memory变量中,它被设置为896MB。大于896MB边界以上的页框并不映射在内核线性地址空间的第4个GB中,因此无法高端内存页框只能返回页框描述符对应的线性地址。

因此在32位系统上,ZONE_HIGHMEN管理区总是空的。

但是问题在于不被映射的地址无法被内核访问,那就要想办法能够访问高端内存页框。因此使用线性地址空间的最后128MB中的一部分专门用于高端内存页框的映射,通过重复的映射,使得整个高端内存能够在不同的区域在不同的时间被访问。

内核中使用三种技术访问高端内存,分别是永久内核映射、临时内核映射以及非连续内存分配。本节集中讨论前两种技术。

永久内核映射

永久内核映射允许内核建立高端页框到内核地址空间的长期映射。它们使用主内存中一个专门的页表,其地址存放在pkmap_page_table变量中。

内核使用page_address_htable散列表,该表包含一个page_address_map数据结构,用于为高端内存中的每一个页框进行当前映射,其表项包含512或1024项,因此内核一次最多访问2MB或4MB的高端内存。

page_address_htable散列表记录高端内存页框与永久内核映射包含的线性地址之间的联系,该数据结构还包含一个指向页描述符的指针和分配给该页框的线性地址。

 

The end.

发表评论

电子邮件地址不会被公开。 必填项已用*标注