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?