图解Linux内存管理_整体架构

图解Linux内存管理_整体架构

目录

大家好,这里是物联网心球。

前面我们学习了很多Linux内存方面的知识,比如:虚拟地址空间,进程空间,内存映射,页表机制等,我们学了这么多知识,似乎对Linux内存似懂非懂,为什么会出现这样的问题?原因在于我们缺乏对物理内存的了解,由于缺乏物理内存管理相关的知识,我们对于内存管理没有形成体系,所以才会似懂非懂。

图解Linux内存管理_整体架构 图1

本文我们抛弃八股文的学习方式,以一种创新的方式来学习Linux内存管理,我们基于物理地址来学习Linux内存管理。

1.UMA和NUMA架构


UMA(Uniform Memory Access)和NUMA(Non-Uniform Memory Access)是两种不同的内存访问架构。

1.1 UMA架构


UMA是一种对称多处理(SMP)系统的内存访问架构,它指的是所有处理器对内存的访问具有相同的延迟。

在UMA系统中,所有处理器共享同一总线或交叉点,可以直接访问共享内存,这意味着无论哪个处理器访问内存,延迟都是相同的,UMA适用于小规模的多处理器系统。

图解Linux内存管理_整体架构 图2

1.2 NUMA架构


NUMA是一种非对称多处理(NUMA)系统的内存访问架构,它指的是不同处理器对内存的访问延迟可能不同。

在NUMA系统中,每个处理器都有自己的本地内存和本地内存控制器,可以更快地访问本地内存。

如果一个处理器要访问其他处理器的本地内存,需要通过QPI总线去访问,这样延迟就会增加。

NUMA适用于大规模的多处理器系统,NUMA架构将物理内存分为一个个内存节点,内存节点和内存节点之间的物理地址有可能是不连续的,同一内存节点物理内存物理地址是连续的。

图解Linux内存管理_整体架构 图3

小节:

  • 不管是UMA和NUMA架构,物理内存的物理地址都是唯一的。

  • UMA架构可以理解为NUMA架构的一个节点,是NUMA架构的一种特殊情况。

2.物理内存管理


我们围绕物理地址来理解物理内存,物理内存管理其实是对物理地址的管理。

2.1 物理地址


物理地址是物理内存中每个字节的身份信息,我们要对物理内存进行读写必须要知道物理地址,每块物理内存区域通过起始地址和大小表示,每个物理地址的用途从硬件诞生就已经确定下来,如下图:

图解Linux内存管理_整体架构 图4

备注:图片来自《奔跑吧Linux内核卷1》

我们明确了物理地址的作用后,Linux内存管理可以简化为物理地址管理,如何管理物理地址,我们将用到页机制。

2.2 page有什么用?


页机制的核心是页(page),page为物理内存管理的最小单位。

如果每个物理地址我们都花精力去管理,管理成本会非常高,也非常不现实,所以需要一种高效且灵活的机制来管理物理地址,这种机制我们称为页机制。

图解Linux内存管理_整体架构 图5

如上图,物理内存被划分成一个个固定大小的页,页的大小通常为4KB,Linux通过struct page结构体来表示一个物理页,struct page定义如下:

图解Linux内存管理_整体架构 图6

struct page实际大小大概为40B,并没有4KB大小,所以struct page只是物理页的映射和描述,并不是实际的物理页。

每一个物理页都有一个对应的页号,称为PFN,PFN和物理地址一样,同样是唯一的,通过PFN我们可以定位到物理页的首地址。

2.3 page,PFN,物理地址之间的关系?


(1)PFN和物理地址相互转换

PFN和物理地址遵循一定的转换关系,转换公式如下:

图解Linux内存管理_整体架构 图7

  • PFN转物理地址

一个PFN对应4KB的内存,4KB为4096 Byte,PFN * 4096为PFN对应的物理页的首地址(物理地址),PFN * 4096 = PFN « 12。

  • 物理地址转PFN

PFN = 物理地址 / 4096 = 物理地址 » 12。

(2)page和PFN相互转换

page和PFN相互转换需要结合内存模型讨论。

(3)page和物理地址转换

page和物理地址转换,需要借助PFN完成,page和物理地址不能直接转换,需要先转换成PFN,再通过PFN完成转换。

3.三种内存模型


Linux内存模型分为:

  • 平坦内存模型(FLATMEM)

  • 非连续内存模型(DISCONTIGMEM)

  • 稀疏内存模型(SPARSEMEM)

我们不要被这些高大上的名字吓住,其实这些内存模型都是通过数组实现,不同的内存模型对page的组织方式不同。

3.1 平坦内存模型

平坦内存模型是指在Linux操作系统中,物理内存被视为一个连续的、线性的地址空间,而不是分段或分页的方式,这种模型使得内存管理更加简单和高效。

图解Linux内存管理_整体架构 图8

平坦内存模式采用struct pglist_data指针数组表示,每个数组元素都是一个struct pglist_data对象,struct pglist_data对象表示一个内存节点,内存节点就是我们前面讲到的NUMA架构内存节点,struct pglist_data对象有一个node_mem_map成员,该成员是一个struct page指针,指向一个页表。

平坦内存模型page和PFN转换:

图解Linux内存管理_整体架构 图9

平坦内存模式只有一个节点0,平坦内存模型物理起始地址偏移为0。

  • PFN转page

PFN转page首先得找到页表起始地址,计算方式如下:

struct page *mem_map = node_data[0]->node_mem_map;

PFN和ARCH_PFN_OFFSET的差值为数组索引值,页表起始地址+数组索引值得到page地址。

  • page转PFN

page地址和mem_map地址的差值为数组索引值,数组索引值+ARCH_PFN_OFFSET为PFN值。

3.2 非连续内存模型


不连续内存模型是指内存空间被分割成多个不连续的区域,每个区域具有不同的物理地址范围。

不连续内存模型可以提供更灵活的内存管理方式,但也增加了程序设计和实现的复杂性。

图解Linux内存管理_整体架构 图10

非连续内存模型和平坦内存模型都是采用struct pglist_data指针数组来实现,非连续内存模型通常来说有多个节点,每个节点之间的物理内存的物理地址不连续,平坦内存模型可以理解为一个节点的非连续内存模型。

非连续内存模型和平坦内存模型page和PFN转换方式是一样的。

图解Linux内存管理_整体架构 图11

非连续内存模型的mem_map和ARCH_PFN_OFFSET每个节点都不一样。

3.3 稀疏内存模型


稀疏内存模型是一种用于管理大容量内存的机制,它允许系统在物理内存不连续的情况下有效地使用内存空间。稀疏内存模型中,内存被划分为多个区域,每个区域可以包含不同数量的页框。

稀疏内存模型的主要目的是解决内存碎片化的问题。在传统的连续内存模型中,当系统中有大量空闲页框但它们不连续时,无法有效利用这些内存空间,而稀疏内存模型通过将内存划分为多个区域,可以更灵活地管理内存碎片,从而提高内存利用率。

稀疏内存模型的管理单位为mem_section,定义如下:

图解Linux内存管理_整体架构 图12

section_mem_map为页表起始地址,一个struct mem_section代表一块连续的物理内存区域,每个mem_section都有一个对应的编号,通过section编号可以定位到对应的mem_section。

图解Linux内存管理_整体架构 图13

稀疏内存模型page和PFN转换方式:

图解Linux内存管理_整体架构 图14

  • page转PFN

struct page结构体flags成员记录了page的section编号,通过flags解析出section编号,再通过section编号定位到mem_section对象,mem_section对象成员section_mem_map为页表地址,page地址和section_mem_map之间的差值为PFN。

  • PFN转page

通过PFN获取到section编号,通过section编号定位到mem_section对象,section_mem_map + PFN获取到page地址。

← 返回文章列表