此处接前文,分析free_area_init_nodes()函数最后部分,分析其末尾的循环:

for_each_online_node(nid) {

    pg_data_t *pgdat = NODE_DATA(nid);

    free_area_init_node(nid, NULL,

            find_min_pfn_for_node(nid), NULL);

    /* Any memory on that node */

    if (pgdat->node_present_pages)

        node_set_state(nid, N_MEMORY);

    check_for_memory(pgdat, nid);

}

这里面的关键函数是free_area_init_node(),其入参find_min_pfn_for_node()用于获取node节点中最低的内存页框号。

而free_area_init_node()其实现:

【file:/mm/page_alloc.c】
void __paginginit free_area_init_node(int nid, unsigned long *zones_size,
unsigned long node_start_pfn, unsigned long *zholes_size)
{
pg_data_t *pgdat = NODE_DATA(nid);
unsigned long start_pfn = 0;
unsigned long end_pfn = 0; /* pg_data_t should be reset to zero when it's allocated */
WARN_ON(pgdat->nr_zones || pgdat->classzone_idx); pgdat->node_id = nid;
pgdat->node_start_pfn = node_start_pfn;
init_zone_allows_reclaim(nid);
#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
get_pfn_range_for_nid(nid, &start_pfn, &end_pfn);
#endif
calculate_node_totalpages(pgdat, start_pfn, end_pfn,
zones_size, zholes_size); alloc_node_mem_map(pgdat);
#ifdef CONFIG_FLAT_NODE_MEM_MAP
printk(KERN_DEBUG "free_area_init_node: node %d, pgdat %08lx, node_mem_map %08lx\n",
nid, (unsigned long)pgdat,
(unsigned long)pgdat->node_mem_map);
#endif free_area_init_core(pgdat, start_pfn, end_pfn,
zones_size, zholes_size);
}

该函数中,其中init_zone_allows_reclaim()用于计算评估内存管理区是否可回收以及合适的node节点数,如果非NUMA环境,则该函数为空。而基于CONFIG_HAVE_MEMBLOCK_NODE_MAP的配置下,接下来将是get_pfn_range_for_nid():

【file:/mm/page_alloc.c】
/**
* get_pfn_range_for_nid - Return the start and end page frames for a node
* @nid: The nid to return the range for. If MAX_NUMNODES, the min and max PFN are returned.
* @start_pfn: Passed by reference. On return, it will have the node start_pfn.
* @end_pfn: Passed by reference. On return, it will have the node end_pfn.
*
* It returns the start and end page frame of a node based on information
* provided by an arch calling add_active_range(). If called for a node
* with no available memory, a warning is printed and the start and end
* PFNs will be 0.
*/
void __meminit get_pfn_range_for_nid(unsigned int nid,
unsigned long *start_pfn, unsigned long *end_pfn)
{
unsigned long this_start_pfn, this_end_pfn;
int i; *start_pfn = -1UL;
*end_pfn = 0; for_each_mem_pfn_range(i, nid, &this_start_pfn, &this_end_pfn, NULL) {
*start_pfn = min(*start_pfn, this_start_pfn);
*end_pfn = max(*end_pfn, this_end_pfn);
} if (*start_pfn == -1UL)
*start_pfn = 0;
}

此函数主要是将内存node节点的起始和末尾页框号返回给接下来的calculate_node_totalpages()来使用。

calculate_node_totalpages()实现:

【file:/mm/page_alloc.c】
static void __meminit calculate_node_totalpages(struct pglist_data *pgdat,
unsigned long node_start_pfn,
unsigned long node_end_pfn,
unsigned long *zones_size,
unsigned long *zholes_size)
{
unsigned long realtotalpages, totalpages = 0;
enum zone_type i; for (i = 0; i < MAX_NR_ZONES; i++)
totalpages += zone_spanned_pages_in_node(pgdat->node_id, i,
node_start_pfn,
node_end_pfn,
zones_size);
pgdat->node_spanned_pages = totalpages; realtotalpages = totalpages;
for (i = 0; i < MAX_NR_ZONES; i++)
realtotalpages -=
zone_absent_pages_in_node(pgdat->node_id, i,
node_start_pfn, node_end_pfn,
zholes_size);
pgdat->node_present_pages = realtotalpages;
printk(KERN_DEBUG "On node %d totalpages: %lu\n", pgdat->node_id,
realtotalpages);
}

其中zone_spanned_pages_in_node():

【file:/mm/page_alloc.c】
/*
* Return the number of pages a zone spans in a node, including holes
* present_pages = zone_spanned_pages_in_node() - zone_absent_pages_in_node()
*/
static unsigned long __meminit zone_spanned_pages_in_node(int nid,
unsigned long zone_type,
unsigned long node_start_pfn,
unsigned long node_end_pfn,
unsigned long *ignored)
{
unsigned long zone_start_pfn, zone_end_pfn; /* Get the start and end of the zone */
zone_start_pfn = arch_zone_lowest_possible_pfn[zone_type];
zone_end_pfn = arch_zone_highest_possible_pfn[zone_type];
adjust_zone_range_for_zone_movable(nid, zone_type,
node_start_pfn, node_end_pfn,
&zone_start_pfn, &zone_end_pfn); /* Check that this node has pages within the zone's required range */
if (zone_end_pfn < node_start_pfn || zone_start_pfn > node_end_pfn)
return 0; /* Move the zone boundaries inside the node if necessary */
zone_end_pfn = min(zone_end_pfn, node_end_pfn);
zone_start_pfn = max(zone_start_pfn, node_start_pfn); /* Return the spanned pages */
return zone_end_pfn - zone_start_pfn;
}

其主要是统计node管理节点的内存跨度,该跨度不包括movable管理区的,里面调用的adjust_zone_range_for_zone_movable()则是用于剔除movable管理区的部分。

另外的zone_absent_pages_in_node():

【file:/mm/page_alloc.c】
/* Return the number of page frames in holes in a zone on a node */
static unsigned long __meminit zone_absent_pages_in_node(int nid,
unsigned long zone_type,
unsigned long node_start_pfn,
unsigned long node_end_pfn,
unsigned long *ignored)
{
unsigned long zone_low = arch_zone_lowest_possible_pfn[zone_type];
unsigned long zone_high = arch_zone_highest_possible_pfn[zone_type];
unsigned long zone_start_pfn, zone_end_pfn; zone_start_pfn = clamp(node_start_pfn, zone_low, zone_high);
zone_end_pfn = clamp(node_end_pfn, zone_low, zone_high); adjust_zone_range_for_zone_movable(nid, zone_type,
node_start_pfn, node_end_pfn,
&zone_start_pfn, &zone_end_pfn);
return __absent_pages_in_range(nid, zone_start_pfn, zone_end_pfn);
}

该函数主要用于计算内存空洞页面数的。完了将会得到物理页面总数并在calculate_node_totalpages()中将页面总数打印出来:

再往下的mminit_verify_pageflags_layout()函数主要用于内存初始化调测使用的,由于未开启CONFIG_DEBUG_MEMORY_INIT配置项,此函数为空。而setup_nr_node_ids()是用于设置内存节点总数的,此处如果最大节点数MAX_NUMNODES不超过1,则是空函数。

free_area_init_nodes()函数末了还有一个遍历各个节点做初始化的操作,暂且留待后面再分析。

Linux-3.14.12内存管理笔记【构建内存管理框架(3)】的更多相关文章

  1. Linux-3.14.12内存管理笔记【内存泄漏检测kmemleak示例】【转】

    本文转载自:http://blog.chinaunix.net/uid-26859697-id-5758037.html 分析完kmemleak实现后,照常实验一下,以确定功能正常. 如kmemche ...

  2. Linux中的Buffer Cache和Page Cache echo 3 > /proc/sys/vm/drop_caches Slab内存管理机制 SLUB内存管理机制

    Linux中的Buffer Cache和Page Cache echo 3 > /proc/sys/vm/drop_caches   Slab内存管理机制 SLUB内存管理机制 http://w ...

  3. 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配

    垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己 ...

  4. Win3内存管理之私有内存跟共享内存的申请与释放

    Win3内存管理之私有内存跟共享内存的申请与释放 一丶内存简介私有内存申请 通过上一篇文章.我们理解了虚拟内存与物理内存的区别. 那么我们有API事专门申请虚拟内存与物理内存的. 有私有内存跟共享内存 ...

  5. JVM自动内存管理机制——Java内存区域(下)

    一.虚拟机参数配置 在上一篇<Java自动内存管理机制——Java内存区域(上)>中介绍了有关的基础知识,这一篇主要是通过一些示例来了解有关虚拟机参数的配置. 1.Java堆参数设置 a) ...

  6. 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法

    垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己 ...

  7. Linux-3.14.12内存管理笔记【构建内存管理框架(1)】

    传统的计算机结构中,整个物理内存都是一条线上的,CPU访问整个内存空间所需要的时间都是相同的.这种内存结构被称之为UMA(Uniform Memory Architecture,一致存储结构).但是随 ...

  8. Linux-3.14.12内存管理笔记【构建内存管理框架(5)】

    前面已经分析了内存管理框架的构建实现过程,有部分内容未完全呈现出来,这里主要做个补充. 如下图,这是前面已经看到过的linux物理内存管理框架的层次关系. 现着重分析一下各个管理结构体的成员功能作用. ...

  9. Linux-3.14.12内存管理笔记【构建内存管理框架(2)】

    前面构建内存管理框架,已经将内存管理node节点设置完毕,接下来将是管理区和页面管理的构建.此处代码实现主要在于setup_arch()下的一处钩子:x86_init.paging.pagetable ...

随机推荐

  1. C语言笔记 03_常量&存储类

    常量 常量是固定值,在程序执行期间不会改变.这些固定的值,又叫做字面量. 常量可以是任何的基本数据类型,比如整数常量.浮点常量.字符常量,或字符串字面值,也有枚举常量. 整数常量 整数常量可以是十进制 ...

  2. Spring Boot Failed to load resource: the server responded with a status of 404 ()

    出现错误: Failed to load resource: the server responded with a status of 404 () 但是其他页面正常显示: 原因: 浏览器看一下:  ...

  3. [转]UiPath Deployment Architecture

    本文转自:https://dotnetbasic.com/2019/08/uipath-deployment-architecture.html We will learn step by step ...

  4. 【漏洞预警】Redis 4.x/5.x 远程命令执行高危漏洞

    2019年7月09日,阿里云应急响应中心监测到有安全研究人员披露Redis 4.x/5.x 远程命令执行高危漏洞利用代码工具.针对未授权或弱口令的Redis服务,攻击者通过构造特定请求,成功利用漏洞可 ...

  5. Maven详解(非原创)

    文章大纲 一.maven功能介绍二.maven整合javaweb案例三.私服应用(了解)四.总结五.相关资料下载六.参考文章 一.maven功能介绍 1. maven基本介绍   Maven的Apac ...

  6. css字体效果

    text-shadow还没有出现时,大家在网页设计中阴影一般都是用photoshop做成图片,现在有了css3可以直接使用text-shadow属性来指定阴影.这个属性可以有两个作用,产生阴影和模糊主 ...

  7. 07-Django视图进阶

    1.调试模式 Django项目下的settings.py 默认是DEBUG=True,开发的时候一般要开启调试模式,当项目完成发布必须要改成False,否则会暴露网站的配置信息,修改以下两行: # D ...

  8. springioc之依赖注入

    1.1.2  IoC能做什么 IoC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合.更优良的程序.传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类 ...

  9. go语言面向对象之方法

    1.实现方法 package main import "fmt" //在面向对象编程中,一个对象其实就是一个简单的值或者一个变量,在这个 //对象中包含一些函数 //这种带有接受者 ...

  10. Nginx配置Tomcat8反向代理出现 java.lang.IllegalArgumentException: The character [_] is never valid in a domain name.

    在配置Nginx的反向代理,访问反向代理的路径而出现了异常 java.lang.IllegalArgumentException: The character [_] is never valid i ...