Node-Zone-Page

Node, Zone, Page是内核中内存管理模块非常常见的几个概念,但是一直以来都不清楚其究竟是什么含义,之间又有什么联系。我想很多人也有类似我的困惑。今天我就装个大头,帮助大家理理这里面的关系。

一张经典的图

这里写图片描述

此图来自Describing Physical Memory

这张图想必有探索过内存管理的同学可能都会见过,但是估计大部分看不懂,或者知道个一知半解。因为我以前看的时候也看不懂,这讲的是个毛?好像是有点那个意思,但是是如何和实际上的内存对应起来的呢?

希望看完这篇文章后,能对这张图能够有更多一点的了解。

Node和Zone的概念

我想先讲一下这两个概念之间的区别,或许有了这两者之间的概念,才能够更好的理解内存管理。至少我走过了这么多弯路之后,才发现自己之前的概念是错误的。

Node

Zone

两者结合在一起

让我尝试用两句话来定义Node和Zone

  • Node是从内存亲和性出发的定义,看到的表现是地址上的分布,但实际上不是从地址出发的定义。

  • Zone是一个从地址大小出发的定义,不论系统上的内存大小是多少,每个zone的空间是一定的。比如ZONE_DMA一定是16M一下的空间。

根据以上的定义其实可以得出,在某些node上的zone是空的。比如你仔细看上面几个图,node1上就不会存在ZONE_DMA的空间。

我的一张图

在文章的一开始,我们就看到了一张经典的对内存管理结构的图。对node和zone有了一定理解之后,尝试将这两者的关系,画成图。其中node_data对应的是pg_data_t。

沿用之前6G内存系统的例子,这时内核初始化完的结构如下:

图中有几个点值得注意:

  • ZONE_DMA和ZONE_DMA32的大小是固定的

  • Node0上的ZONE_NORMAL是空的

  • Node2上的ZONE_DMA是空的

怎么样,这样看是不是清楚了一点?

验证的源代码

来,给你个源代码,这样你自己回去也可以试试。

注: 输出的数值会和理论值有差别

PS: free_area_init()中也有相关的日志输出。

划分node/zone的边界

既然每个node都由pgdat表示,那么就需要看看这部分信息是如何初始化的。

函数free_area_init是负责初始化的,这里我们主要观察该函数的行为。而该函数在整个系统初始化过程的位置参见memblock中的初始化流程

相关日志

内核启动过程中,我们可以通过free_area_init()中输出的日志观察每个node/zone所使用的区域。

日志中搜索的关键字是:"Zone ranges:", "Early memory node ranges"。

运行起来后,能在文件/proc/zoneinfo中看到更多的数据。

ZONE_MOVABLE

这次花了点时间看了下ZONE_MOVABLE,本来以为这个zone和其他的没有什么区别。实际不然。

这个zone的大小,在x86上,是计算出来的,而不是像其他的zone有明确的事先边界。这里我把和ZONE_MOVABLE计算相关的代码在下面着重标出来。

开启ZONE_MOVABLE的方式

默认情况下我们看不到这个zone的存在,有下面几种方式可以开启:

  • movable_node

  • kernelcore=50%

其实都是在内核命令行里加参数,具体可以看函数find_zone_movable_pfns_for_nodes()。全都在里面了。

思考题

每个page作为链表元素链接在了free_list上,那page数据结构本身放在哪里呢?你猜的到吗?

Last updated

Was this helpful?