Linux memfree 的计算逻辑
一.Linux 系统中的 memfree
表示系统中当前可用的物理内存大小,其计算逻辑主要在内核源码中实现。以下是关键代码逻辑和计算方法的分析。
MemFree 与 global_node_page_state(NR_FREE_PAGES) 的关系
在 Linux 内核中,
MemFree
通常指系统当前可用的空闲内存量,而global_node_page_state(NR_FREE_PAGES)
是内核中用于计算空闲页数的函数。两者确实存在直接关联,可以理解为MemFree
的值主要由global_node_page_state(NR_FREE_PAGES)
计算得出。
关键点说明
-
global_node_page_state
的作用
该函数统计所有 NUMA 节点的空闲页数总和,返回全局空闲页数。它是内核内存管理的核心接口之一。 -
MemFree
的局限性
MemFree
仅包含完全未使用的内存,不包含缓存(如Buffers
/Cached
)或可回收内存(如Slab
)。实际可用内存可能需要结合其他指标(如MemAvailable
)。 -
与
/proc/meminfo
的关系
/proc/meminfo
中的MemFree
字段直接来源于上述计算,用户空间工具(如free
命令)会读取该文件显示空闲内存。
二.memfree 与 nr_free_pages 的关系
memfree
是通过 global_node_page_state(NR_FREE_PAGES)
计算得到的,而 /proc/zoneinfo
中的 nr_free_pages
是每个内存区域(zone)的统计值。两者本质上是等价的,但统计范围和层级不同。
global_node_page_state(NR_FREE_PAGES)
是汇总所有节点(node)和所有区域(zone)的空闲页面,而 /proc/zoneinfo
中的 nr_free_pages
是按区域细分的统计值。
关键区别
统计范围
global_node_page_state(NR_FREE_PAGES)
:全局统计,包含所有节点和区域。/proc/zoneinfo
中的nr_free_pages
:按区域统计,每个区域的空闲页面单独列出。
数据来源
NR_FREE_PAGES
是内核中的一个全局计数器,通过vm_stat[]
数组维护。/proc/zoneinfo
直接从每个区域的struct zone
中读取nr_free_pages
字段。
验证方法
如果需要验证两者的等价性,可以通过以下方式:
- 将
/proc/zoneinfo
中所有区域的nr_free_pages
相加,结果应与global_node_page_state(NR_FREE_PAGES)
一致。 - 使用
grep "nr_free_pages" /proc/zoneinfo
查看各区域的空闲页面,再与free
命令或/proc/meminfo
中的MemFree
对比。
代码层面的联系
在内核源码中,global_node_page_state(NR_FREE_PAGES)
最终会调用 vm_stat[NR_FREE_PAGES]
,而 /proc/zoneinfo
中的 nr_free_pages
来自 zone->nr_free
。两者的数据源头是统一的,只是聚合方式不同。
------------------------------------
相关内核代码
memfree
的计算通常在内核的 mm/vmstat.c
或 fs/proc/meminfo.c
中实现。以下是 fs/proc/meminfo.c
中的关键代码片段:
static int meminfo_proc_show(struct seq_file *m, void *v)
{struct sysinfo i;unsigned long committed;long cached;long available;si_meminfo(&i); // 获取系统内存信息cached = global_node_page_state(NR_FILE_PAGES) - total_swapcache_pages();available = si_mem_available(); // 计算可用内存committed = percpu_counter_read_positive(&vm_committed_as);seq_printf(m, "MemTotal: %8lu kB\n", i.totalram << (PAGE_SHIFT - 10));seq_printf(m, "MemFree: %8lu kB\n", i.freeram << (PAGE_SHIFT - 10));seq_printf(m, "MemAvailable: %8lu kB\n", available << (PAGE_SHIFT - 10));// 其他内存信息输出...
}
关键计算步骤
-
调用
si_meminfo
获取基础内存信息
si_meminfo
函数从内核的全局变量中读取内存统计信息,包括总内存 (totalram
)、空闲内存 (freeram
)、缓冲区内存 (bufferram
) 等。freeram
直接来自struct sysinfo
,表示未使用的物理内存。 -
空闲内存 (
freeram
) 的来源
空闲内存 (freeram
) 的值来自内核的全局变量totalram_pages - total_used_pages
,其中:totalram_pages
是系统总物理内存页数。total_used_pages
包括已分配的页面、缓存、缓冲区等。
-
单位转换
在输出到/proc/meminfo
时,空闲内存 (freeram
) 的值会从页数转换为 KB:i.freeram << (PAGE_SHIFT - 10)
PAGE_SHIFT
是页大小的位移数(通常为 12,表示 4KB 页)。PAGE_SHIFT - 10
将页数转换为 KB(因为2^12 = 4096
,而2^10 = 1024
)。
更详细的计算逻辑
空闲内存 (MemFree
) 不包括缓存和缓冲区,但可以通过 si_mem_available()
计算更精确的“可用内存” (MemAvailable
),该函数会考虑缓存的可回收部分。以下是 si_mem_available()
的简化逻辑:
unsigned long si_mem_available(void)
{long available = global_zone_page_state(NR_FREE_PAGES); // 空闲页available += global_node_page_state(NR_FILE_PAGES) - total_swapcache_pages(); // 可回收缓存available += vm_node_stat[NR_SLAB_RECLAIMABLE]; // 可回收 Slabreturn available;
}
总结
MemFree
直接来自内核的freeram
,表示完全未使用的物理内存。- 计算逻辑集中在
fs/proc/meminfo.c
和mm/vmstat.c
中。 - 单位转换通过位移操作完成,将页数转换为 KB。
MemAvailable
是更全面的指标,包括可回收的缓存和 Slab 内存。
启动应用时分配 Pages 的考量
启动应用时所需分配的 Pages 数量取决于应用的内存需求和系统当前的内存状态。关键因素包括:
- 应用的工作集大小(常驻内存部分)
- 动态内存需求(如堆、栈、文件映射等)
- 系统内存压力(通过
/proc/zoneinfo
等指标判断)
典型情况下:
- 轻量级应用可能需要几十MB(约数千个4KB pages)
- 大型应用可能消耗数百MB到GB级别内存
/proc/zoneinfo
与 nr_free_pages
的关系
当应用启动并分配内存时:
nr_free_pages
会减少,反映系统可用物理内存的消耗- 分配可能涉及多个内存域(DMA/DMA32/Normal)
- 内存回收机制(kswapd)可能在低水位时触发
监控示例:
# 查看各zone的剩余pages cat /proc/zoneinfo | grep -E "Node|pages free"
高级调试工具
检查page分配失败日志:
dmesg | grep -i "out of memory"
实时监控page分配:
watch -n 1 "cat /proc/buddyinfo"
注意:实际分配行为受内核版本、内存碎片化和NUMA策略等多因素影响,需结合具体场景分析。