1. 从生活水塔到内核水线:理解内存管理的“警戒水位”
大家好,我是老K,在ARM服务器和嵌入式系统里折腾了十几年内存管理。今天咱们不聊那些虚头巴脑的理论,就从一个生活场景说起。想象一下你家楼顶的水塔,它负责给整栋楼供水。水塔里有个“低水位”标记,当水位降到这个标记以下,控制系统就会自动启动水泵往水塔里注水;等水位恢复到“高水位”标记,水泵就自动停止。这个“低水位”就是触发补水动作的警戒线,而“高水位”就是安全的停止线。
Linux内核管理内存,尤其是物理内存的每个区域(Zone),用的就是一模一样的思路。只不过,内核这个“水塔管理员”更精细,它设定了三条水位线:最低水线(WMARK_MIN)、低水线(WMARK_LOW) 和 高水线(WMARK_HIGH)。这三条线,直接决定了系统何时开始回收内存、以何种方式回收,以及回收多少才算完事。这对于追求极致稳定性和性能的ARM64服务器、手机或者物联网设备来说,是底层性能调优的“命门”之一。
很多朋友在性能调优时,只关注CPU使用率,却忽略了内存水线这个沉默的“看门人”。结果就是,系统可能看起来内存还很充裕(MemFree不少),但应用却莫名卡顿,甚至突然被OOM(内存耗尽)杀手干掉。这背后的“元凶”,往往就是水线值设置不合理,导致内存回收机制要么“反应迟钝”,要么“过度亢奋”。今天,我就带大家钻进内核,看看在ARM64架构下,这三条水位线是怎么画出来的,又是如何像扳机一样,扣动kswapd(内核后台回收线程)和直接回收(Direct Reclaim)这两把“枪”的。
2. 深入Zone水线:三条线背后的内存状态
在Linux内核中,物理内存被划分为几个Zone。对于咱们关注的ARM64架构,最常见的是ZONE_DMA(用于老式DMA设备)、ZONE_DMA32(用于32位地址DMA设备)和ZONE_NORMAL(普通内存)。每个Zone都是独立的水塔,拥有自己的一套水位标记。
2.1 水线三档位的定义与默认关系
这三个档位不是随便画的,它们定义了内存的四种压力状态:
- 充裕状态:空闲内存 > 高水线(WMARK_HIGH)。此时系统内存充足,kswapd线程安心睡觉。
- 轻微压力:空闲内存介于 低水线(WMARK_LOW) 和 高水线(WMARK_HIGH) 之间。这是一个预警区间,内核会开始“琢磨”是不是该做点啥了。
- 压力状态:空闲内存介于 最低水线(WMARK_MIN) 和 低水线(WMARK_LOW) 之间。这时,内核认为内存已经有点紧张了。
- 严重短缺:空闲内存 < 最低水线(WMARK_MIN)。这是紧急状态,系统必须立刻采取行动。
它们三者的默认比例关系是固定的:WMARK_MIN : WMARK_LOW : WMARK_HIGH = 1 : 1.25 : 1.5。也就是说,如果WMARK_MIN是100页,那么WMARK_LOW就是125页,WMARK_HIGH就是150页。这个比例是内核默认行为的基础。
2.2 结构体中的水线:struct zone 揭秘
光知道概念不行,得看看代码里它们藏在哪。每个Zone的水线值,都记录在一个关键的内核数据结构 struct zone 里:
struct zone {
/* 水位值数组,WMARK_MIN, WMARK_LOW, WMARK_HIGH 就存在这里 */
unsigned long watermark[NR_WMARK];
/* 为高阶原子分配保留的页面数 */
unsigned long nr_reserved_highatomic;
/* 为更高位Zone保留的内存页数组,防止低位Zone被掏空 */
long lowmem_reserve[MAX_NR_ZONES];
// ... 其他很多字段
};
enum zone_watermarks {
WMARK_MIN


7764

被折叠的 条评论
为什么被折叠?



