关于linux 内存碎片指数

本文介绍Linux系统中如何通过extfrag_index参数评估不同节点、zone及order的内存碎片程度,并展示了如何利用内核选项CONFIG_DEBUG_FS与CONFIG_COMPACTION启用此功能。此外,还解释了碎片指数的具体含义及其在内存管理中的作用。

linux针对每一个node的每个zone的每个order,都有一个碎片指数来描述当前的碎片程度,也就是

extfrag_index 参数:
extfrag_index这个要展示出来,需要内核编译了两个选项,即:

#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_COMPACTION)
否则不会生成这个文件。
[root@localhost ~]#    grep CONFIG_DEBUG_FS /boot/config-3.10.0-693.5.2.el7.x86_64 
CONFIG_DEBUG_FS=y
[root@localhost ~]# grep CONFIG_COMPACTION /boot/config-3.10.0-693.5.2.el7.x86_64 
CONFIG_COMPACTION=y

如果确定已经编译进入内核,但是也看不到/sys/kernel/debug/下的数据,那说明没有挂载,或者挂载的路径不是/sys/kernel/debug/,如果没有挂载则需要挂载一下:

mount -t debugfs none  /sys/kernel/debug

然后,在linux里面展示如下:

[root@localhost ~]# cat /sys/kernel/debug/extfrag/extfrag_index
Node 0, zone      DMA -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 
Node 0, zone    DMA32 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 
Node 0, zone   Normal -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 0.995 0.998 
Node 1, zone   Normal -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 0.988 0.994 0.997 

那这些数据怎么理解呢?

我们先来看一下打印这些数据的函数:

static void extfrag_show_print(struct seq_file *m,
                    pg_data_t *pgdat, struct zone *zone)
{
    unsigned int order;
    int index;

    /* Alloc on stack as interrupts are disabled for zone walk */
    struct contig_page_info info;

    seq_printf(m, "Node %d, zone %8s ",
                pgdat->node_id,
                zone->name);
    for (order = 0; order < MAX_ORDER; ++order) {
        fill_contig_page_info(zone, order, &info);
        index = __fragmentation_index(order, &info);
        seq_printf(m, "%d.%03d ", index / 1000, index % 1000);------------可以看出,"."前面是__fragmentation_index返回值的除数,后面是余数 
}
seq_putc(m, '\n');
}

如下就是计算碎片指数的函数:

static int __fragmentation_index(unsigned int order, struct contig_page_info *info)
{
    unsigned long requested = 1UL << order;

    if (!info->free_blocks_total)------------没有内存,返回0,都没有内存,谈何碎片
        return 0;

    /* Fragmentation index only makes sense when a request would fail */
    if (info->free_blocks_suitable)------------返回-1000,也就是展示的是-1.000,那么这个时候没有意义,因为内存充足,不关心碎片指数,碎片指数只在申请内存失败的时候有意义
        return -1000;

    /*
     * Index is between 0 and 1 so return within 3 decimal places
     *
     * 0 => allocation would fail due to lack of memory
     * 1 => allocation would fail due to fragmentation
     */
    return 1000 - div_u64( (1000+(div_u64(info->free_pages * 1000ULL, requested))), info->free_blocks_total);
}

可以看出,越靠近1000,则碎片越严重,很容易分配失败。-1000表示内存充足,不需要关心碎片指数。为0代表压根就没free内存了,也不需要关心碎片指数。这两个极端都不需要考虑。

我们来看具体的数据:

[root@localhost ~]# cat /proc/buddyinfo 
Node 0, zone      DMA      0      1      1      1      1      1      1      0      1      1      3 
Node 0, zone    DMA32    187    276    194    232    133     43      7      6      2      2    178 
Node 0, zone   Normal 108231  75779  17645   6950   3437   1991   1100    297      1      0      0 
Node 1, zone   Normal  77511  40265   9424   7355   4124   2210    950      2      0      0      0 
[root@localhost ~]# cat /sys/kernel/debug/extfrag/extfrag_index
Node 0, zone      DMA -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 
Node 0, zone    DMA32 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 
Node 0, zone   Normal -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 0.995 0.998 
Node 1, zone   Normal -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 0.988 0.994 0.997

 

然后迁移合并一下内存:

[root@localhost ~]# echo 1 >/proc/sys/vm/compact_memory 
[root@localhost ~]# cat /proc/buddyinfo                 
Node 0, zone      DMA      0      1      1      1      1      1      1      0      1      1      3 
Node 0, zone    DMA32    563    489    286    211    100     39      7      6      2      1    178 
Node 0, zone   Normal  19109   8235   5752   6181   3805   2486   1572    704    266    127     42 
Node 1, zone   Normal  22730  11342   7692   8589   5944   3296   1300     93     26      5      0 
[root@localhost
~]# cat /sys/kernel/debug/extfrag/extfrag_index Node 0, zone DMA -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 Node 0, zone DMA32 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 Node 0, zone Normal -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 Node 1, zone Normal -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 0.993
总的来看,当有最后一个大页的内存的时候,即4k*2的10次方,也就是4M的连续页面的时候,问题都不大,因为可以拆分页面。

所以如果需要脚本判断当前系统的碎片程度,可以看最后4列的值,如果都为-1.000,没问题,否则多少存在碎片,如果值越大,则越碎。

可以通过配置cat /proc/sys/vm/extfrag_threshold来缓解碎片的问题。这个值默认是500.
如果超过了extfrag_threshold这个值, kswapd就会触发memory compaction . 所以, 这个值设置接近1000, 说明系统在内存碎片的处理倾向于把旧的页换出, 以符合申请的需要; 而设置接近0, 表示系统在内存碎片的处理倾向于做memory compaction,迁移合并及时的话,就可以缓解碎片。但迁移合并是耗性能的,所以可以将其配置为200左右。

转载于:https://www.cnblogs.com/10087622blog/p/8543792.html

<think>我们正在讨论如何检测伙伴系统中的内存碎片问题。根据引用[1][2][3],伙伴系统通过将空闲内存组织成不同大小的块链表(每个块大小是2的幂次个页框)来减少外部碎片,但仍存在内部碎片问题(如分配一页来满足小内存请求)。用户意图是了解如何检测或评估伙伴系统中的内存碎片情况。 检测伙伴系统中的内存碎片可以从以下几个方面进行: ### 1. 通过`/proc/buddyinfo`文件查看伙伴系统状态 这是最直接的检测方法。该文件显示每个内存区域(Zone)中不同大小的连续页框块的数量。 ```bash $ cat /proc/buddyinfo Node 0, zone DMA 1 0 1 0 2 1 1 0 1 1 3 Node 0, zone DMA32 2081 1563 791 374 156 73 25 10 3 0 0 Node 0, zone Normal 1525 1024 512 256 128 64 32 16 8 4 2 ``` - 每行代表一个内存区域(如DMA, DMA32, Normal)。 - 每一列(从第2列开始)表示对应阶数(0到10)的连续空闲页框块的数量。阶数n表示块大小为$2^n$个页框(例如阶0为1页,阶1为2页,阶2为4页,...,阶10为1024页即4MB)。 - **碎片分析**:如果小阶数(如0、1、2)的块数量很多,而大阶数(如5、6、7)的块数量很少,说明系统存在外部碎片,即虽然总空闲内存可能不少,但缺少大的连续内存块。 ### 2. 通过`/proc/pagetypeinfo`获取更详细的信息 该文件提供更详细的内存页类型信息(包括迁移类型),有助于分析碎片。 ```bash $ cat /proc/pagetypeinfo Page block order: 9 Pages per block: 512 Free pages count per migrate type at order 0 1 2 3 4 5 6 7 8 9 10 Node 0, zone DMA, type Unmovable 0 0 0 0 0 0 0 0 0 0 0 Node 0, zone DMA, type Movable 1 0 1 0 2 1 1 0 1 1 3 ... ``` - 这里按迁移类型(Movable, Unmovable, Reclaimable等)显示各阶空闲块数量。 - **碎片分析**:如果不可移动页(Unmovable)散布在内存中,会阻碍大连续内存块的分配。观察不同迁移类型在各阶的分布,可以判断碎片是否由不可移动页导致。 ### 3. 使用`vmstat`命令查看系统内存统计 虽然不直接显示碎片,但`vmstat`的输出可以间接反映碎片情况: ```bash $ vmstat -s ... 1013200 K total memory 789200 K used memory 223000 K active memory 156000 K inactive memory 223000 K free memory # 总空闲内存 10200 K buffer memory ... ``` - 如果`free memory`(总空闲内存)较大,但系统仍然无法分配大块连续内存(如分配大页失败),则可能存在严重的外部碎片。 ### 4. 使用`perf`或`ftrace`跟踪分配失败事件 当分配大块连续内存失败时,内核会记录事件。我们可以使用性能工具跟踪: ```bash # 使用perf监控分配失败事件 $ perf record -e kmem:mm_page_alloc_extfrag -ag $ perf script ``` - 事件`mm_page_alloc_extfrag`在分配过程中因碎片而需要从其他迁移类型"偷取"页面时触发,表明碎片问题。 ### 5. 通过`/proc/sys/vm/extfrag_threshold`调整和监控 该文件控制内核报告外部碎片的阈值(0到1000)。值越低,内核越积极地报告碎片问题。 ```bash $ cat /proc/sys/vm/extfrag_threshold 500 ``` - 当碎片指数超过此阈值时,内核会触发碎片整理(如通过`kswapd`或直接压缩)。监控此值的变化可以辅助判断碎片程度。 ### 6. 使用`sysrq-trigger`强制生成内存报告 通过SysRq键可以强制生成内存状态快照: ```bash # 触发SysRq(需要root权限) $ echo m > /proc/sysrq-trigger # 查看内核日志(dmesg) $ dmesg -T | tail -n 50 ``` 输出会包含伙伴系统各阶内存块的详细信息,类似于`/proc/buddyinfo`但更详细(包括每个CPU的缓存)。 ### 碎片评估指标 我们可以定义碎片指数(Fragmentation Index)来量化外部碎片程度: $$ \text{Fragmentation Index} = 1 - \frac{\text{最大连续空闲块大小}}{\text{总空闲内存}} $$ - 值越接近1,碎片越严重(大块连续内存少)。 - 通过`/proc/buddyinfo`可以计算: ```bash # 示例计算:总空闲页数 = 各阶块数量×块大小(页数)之和 # 最大连续块大小 = 最高阶非零块的大小 ``` ### 结论 检测伙伴系统内存碎片的主要方法: 1. **直接观察**:`/proc/buddyinfo`和`/proc/pagetypeinfo`提供各阶空闲块分布[^3]。 2. **间接推断**:`vmstat`显示总空闲内存与分配失败的矛盾。 3. **事件追踪**:`perf`监控分配失败事件。 4. **主动触发**:SysRq生成详细报告。 > 引用[2]强调:外部碎片本质是空闲内存不连续。以上方法正是通过观察连续空闲块的分布来评估碎片[^2]。 §§相关问题§§ 1. 如何通过`/proc/buddyinfo`计算内存碎片指数? 2. 迁移类型(Migrate Type)如何影响内存碎片? 3. 内核的碎片整理机制(Memory Compaction)是如何工作的? 4. 哪些内核参数可以调整以减少内存碎片? 5. 如何监控透明大页(THP)分配失败与碎片的关系?</think>在 Linux 系统中,检测伙伴系统中的内存碎片主要依靠以下方法和工具,这些方法通过分析不同阶(order)的空闲块分布来评估碎片程度: --- ### 一、核心检测方法 #### 1. **`/proc/buddyinfo`文件**(最直接工具) ```bash cat /proc/buddyinfo ``` **输出示例**: ``` Node 0, zone Normal 35 28 15 9 5 2 1 0 1 2 1 ``` - **含义解析**: - 每一列对应一个**阶(order)**,从 0 到 10(共 11 列) - 阶 `n` 表示块大小为 $2^n$ 个连续页框(如阶0=4KB,阶10=4MB) - 数值表示当前空闲的**连续内存块数量** - **碎片判断**: - **外部碎片**:高阶(如 order≥5)空闲块数量少 → 大块连续内存不足 - **内部碎片**:低阶(如 order=0)空闲块占比高 → 小内存请求浪费整页[^1] #### 2. **`/proc/pagetypeinfo`文件**(进阶分析) ```bash cat /proc/pagetypeinfo ``` **输出关键部分**: ``` Free pages count per migrate type at order 0..10 Type Unmovable Reclaimable Movable Node 0: Zone Normal: 0 12 5 18 1 8 3 17 ... ``` - **分析维度**: - 按**迁移类型**(Movable/Unmovable)分类 - 不可移动页(Unmovable)过多会导致外部碎片加剧[^2] --- ### 二、碎片量化评估指标 #### 1. **碎片指数计算** 通过脚本计算碎片程度: ```bash #!/bin/bash # 计算碎片指数:1 - (最大连续块大小 / 总空闲内存) cat /proc/buddyinfo | awk ' { total_free = 0 max_block = 0 for (i=1; i<=NF; i++) { pages = $i * (2^(i-1)) # 计算阶(i-1)的总页数 total_free += pages if ($i > 0 && (2^(i-1)) > max_block) max_block = 2^(i-1) } frag_index = 1 - (max_block / total_free) print "碎片指数: " frag_index " (0=无碎片, 1=完全碎片化)" }' ``` - **输出示例**:`碎片指数: 0.65` #### 2. **可视化工具** 使用 `buddyinfo` 数据生成图表: ```bash # 安装绘图工具 sudo apt install gnuplot # 生成碎片分布图 cat /proc/buddyinfo | awk '{for(i=1;i<=NF;i++) print i-1,$i}' > data.dat gnuplot -p -e 'plot "data.dat" with linespoints; pause -1' ``` ![buddyinfo碎片分布图](https://via.placeholder.com/400x200?text=高阶块少+低阶块多=高碎片) --- ### 三、内核级检测机制 #### 1. **分配失败事件追踪** ```bash # 监控高阶分配失败事件 perf record -e kmem:mm_page_alloc_extfrag -ag perf script ``` - **触发条件**:当分配高阶内存失败时,内核会尝试从其他迁移类型"窃取"页面[^2] #### 2. **碎片整理触发器** ```bash # 查看当前碎片阈值 cat /proc/sys/vm/extfrag_threshold # 默认500 (0-1000) ``` - 当碎片指数超过此阈值时,内核自动触发**内存压缩**(Compaction) --- ### 四、碎片类型诊断表 | 现象 | 检测方法 | 碎片类型 | 解决方案 | |-------------------------------|-----------------------------|------------|----------------------| | 总空闲内存充足但分配大块失败 | `/proc/buddyinfo` 高阶块少 | **外部碎片** | 内存压缩、重启服务 | | 大量小内存分配导致内存浪费 | `slabtop` 观察对象分配 | **内部碎片** | 使用slab分配器优化 | | 不可移动页阻碍大块分配 | `/proc/pagetypeinfo` | 外部碎片 | 迁移类型隔离 | --- ### 五、优化检测实践 1. **长期监控脚本**: ```bash # 每5分钟记录buddyinfo状态 while true; do date >> /var/log/buddy.log cat /proc/buddyinfo >> /var/log/buddy.log sleep 300 done ``` 2. **告警配置**(通过Prometheus): ```yaml # 监控高阶内存可用性 - alert: HighMemoryFragmentation expr: node_buddy_pages{order=">=5"} < 10 for: 1h labels: severity: warning ``` > 引用[3]指出:伙伴系统通过 **阶分类链表** 管理空闲块,高阶块短缺是外部碎片的直接证据[^3]。 --- ### 结论 检测伙伴系统内存碎片的核心是: 1. 通过 **`/proc/buddyinfo`** 分析各阶空闲块分布 2. 计算 **碎片指数** 量化评估 3. 结合 **迁移类型** 分析碎片成因 4. 监控 **高阶分配失败事件** 主动预警 碎片指数接近 1 或高阶块持续短缺时,需采取内存压缩或调整迁移策略[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值