【Linux 内核 内存管理】物理分配页 ⑤ ( get_page_from_freelist 快速路径调用函数源码分析 | 遍历备用区域列表 | 启用 cpuset 检查判定 | 判定脏页数量 )
文章目录
在 【Linux 内核 内存管理】物理分配页 ② ( __alloc_pages_nodemask 函数参数分析 | __alloc_pages_nodemask 函数分配物理页流程 ) 博客中 , 分析了 __alloc_pages_nodemask
函数分配物理页流程如下 :
首先 , 根据 gfp_t gfp_mask
分配标志位 参数 , 得到 " 内存节点 “ 的 首选 ” 区域类型 " 和 " 迁移类型 " ;
然后 , 执行 " 快速路径 " , 第一次分配 尝试使用 低水线分配 ;
如果上述 " 快速路径 " 分配失败 , 则执行 " 慢速路径 " 分配 ;
上述涉及到了 " 快速路径 " 和 " 慢速路径 "
种物理页分配方式 ;
在 【Linux 内核 内存管理】物理分配页 ④ ( __alloc_pages_nodemask 函数源码分析 | 快速路径 | 慢速路径 | get_page_from_freelist 源码 ) 博客中 , 介绍了 快速路径 主要调用 定义在 Linux 内核源码的 linux-4.12\mm\page_alloc.c#3017 位置的 get_page_from_freelist
函数 , 分配物理页内存 ;
一、遍历备用区域列表
在 函数中 , 主要操作是遍历 备用区域列表 ,
查找满足如下条件的 内存区域 :
① 区域类型 小于等于 首选区域类型 ,
② 内存节点 对应的 节点掩码 位 被设置为 处理状态 ;
static struct page *
get_page_from_freelist(gfp_t gfp_mask, unsigned int order, int alloc_flags,
const struct alloc_context *ac)
{
/*
* Scan zonelist, looking for a zone with enough free.
* See also __cpuset_node_allowed() comment in kernel/cpuset.c.
*/
for_next_zone_zonelist_nodemask(zone, z, ac->zonelist, ac->high_zoneidx,
ac->nodemask){}
}
源码路径 : linux-4.12\mm\page_alloc.c#3029
二、启用 cpuset 检查判定
如果 启用了 cpuset 功能 , 用户设置了 ALLOC_CPUSET
标志位 , 要求 检查 cpuset ,
如果 cpuset 不允许当前 进程 分配 该 内存节点 内存页 , 则直接 continue
, 本次循环 " 备用区域列表 " 操作退出 , 执行下一次循环 ;
static struct page *
get_page_from_freelist(gfp_t gfp_mask, unsigned int order, int alloc_flags,
const struct alloc_context *ac)
{
/*
* Scan zonelist, looking for a zone with enough free.
* See also __cpuset_node_allowed() comment in kernel/cpuset.c.
*/
for_next_zone_zonelist_nodemask(zone, z, ac->zonelist, ac->high_zoneidx,
ac->nodemask){
if (cpusets_enabled() &&
(alloc_flags & ALLOC_CPUSET) &&
!__cpuset_zone_allowed(zone, gfp_mask))
continue;
}
}
源码路径 : linux-4.12\mm\page_alloc.c#3034
相关标志位含义 , 参考 【Linux 内核 内存管理】物理分配页 ③ ( 物理页分配标志位分析 | ALLOC_WMARK_MIN | ALLOC_WMARK_MASK | ALLOC_HARDER ) 博客 ;
ALLOC_CPUSET
宏定义 , 表示 检查 cpuset , 是否允许分配内存页 ;
#define ALLOC_HARDER 0x10 /* try to alloc harder */
#define ALLOC_HIGH 0x20 /* __GFP_HIGH set */
#define ALLOC_CPUSET 0x40 /* check for correct cpuset */
#define ALLOC_CMA 0x80 /* allow allocations from CMA areas */
源码路径 : linux-4.12\mm\internal.h#483
三、判定内存节点的脏页数量
调用者 假如 设置了 __GFP_WRITE
标志位 , 表明 文件系统 写文件 需要 申请一个页缓存 , 需要检查 " 内存节点 “ 中的 ” 脏页数量 " 是否超出了限制 ,
假如 超出了限制 , 也是 不能从 该 内存区域 分配内存 , continue
中断本次遍历 , 继续执行下一次遍历 ;
static struct page *
get_page_from_freelist(gfp_t gfp_mask, unsigned int order, int alloc_flags,
const struct alloc_context *ac)
{
/*
* Scan zonelist, looking for a zone with enough free.
* See also __cpuset_node_allowed() comment in kernel/cpuset.c.
*/
for_next_zone_zonelist_nodemask(zone, z, ac->zonelist, ac->high_zoneidx,
ac->nodemask){
/*
* When allocating a page cache page for writing, we
* want to get it from a node that is within its dirty
* limit, such that no single node holds more than its
* proportional share of globally allowed dirty pages.
* The dirty limits take into account the node's
* lowmem reserves and high watermark so that kswapd
* should be able to balance it without having to
* write pages from its LRU list.
*
* XXX: For now, allow allocations to potentially
* exceed the per-node dirty limit in the slowpath
* (spread_dirty_pages unset) before going into reclaim,
* which is important when on a NUMA setup the allowed
* nodes are together not big enough to reach the
* global limit. The proper fix for these situations
* will require awareness of nodes in the
* dirty-throttling and the flusher threads.
*/
if (ac->spread_dirty_pages) {
if (last_pgdat_dirty_limit == zone->zone_pgdat)
continue;
if (!node_dirty_ok(zone->zone_pgdat)) {
last_pgdat_dirty_limit = zone->zone_pgdat;
continue;
}
}
}
}
源码路径 : linux-4.12\mm\internal.h#3057
相关文章
- Linux系统下内存文件夹的管理(linux内存文件夹)
- Linux系统内存优化工具实用指南(linux内存工具)
- 深入研究:Linux 系统的存储空间查看(linux存储空间查看)
- Linux下如何修改IP地址(linux如何修改ip地址)
- 支持32位Linux最大内存支持之极限(32位linux最大内存)
- Linux内存满了:如何解决?(linux内存满了怎么办)
- 轻松理解Linux分区设置(linux分区设置)
- 占用Linux下查看CPU与内存使用状况(linux查看cpu和内存)
- Linux系统下进程内存限制研究(linux进程内存限制)
- 占用标题:深入了解Linux机器内存占用(查看linux机器内存)
- Linux系统重设密码指南(linux重设密码)
- 管理方法Linux环境下的高性能内存管理技术(linux高端内存)
- Linux下如何解决C语言内存泄漏问题(c内存泄漏linux)
- Linux内存升级:插槽等你来挑战(linux内存插槽)
- Linux 能够处理的最大内存(linux最大内存)
- Linux命令行操作:如何实现关机功能(linux命令行关机)
- Linux系统下动态申请内存的方法(linux申请内存)
- Linux系统中的页表(页表linux)
- Linux网络编程:实现请求转发的方法(linux请求转发)
- Linux时间同步:实现时间精确控制(linux的时间同步)
- 解决Linux内存占用过高问题(linux内存占用大)
- Linux 快速下载文件夹方法(linux 下载 文件夹)
- 深入了解Linux网络员的技能与工作职责(linux网络员)
- Linux查看磁盘空间:简易一步搞定(linux 查看磁盘大小)
- Linux 32系统提升内存性能(linux 32 内存)
- Linux下释放内存的技巧分享(linux 释放内存)
- Linux ln 命令解析:创建符号链接(linux ln 作用)
- Linux系统下数据文件存储位置探索(linux 数据文件位置)
- Linux中CR、LF和CRLF的换行符详解(linux中的换行符)