在linux内核中,所有的物理内存都用struct page结构来描述,这些对象以数组形式存放,而这个数组的地址就是mem_map。内核以节点node为单位,每个node下的物理内存统一管理,也就是说在表示内存node的描述类型struct pglist_data中,有node_mem_map这个成员,其针对平坦型内存
进行描述(CONFIG_FLAT_NODE_MEM_MAP),与此相反的是SPARSEMEM,其稀疏性内存描述。
也就是说,每个内存节点node下,成员node_mem_map是此node下所有内存以struct page描述后,所有这些对象的基地址,这些对象以数组形式存放。
 
如果系统只有一个pglist_data对象,那么此对象下的node_mem_map即为全局对象mem_map。函数alloc_node_mem_map()就是针对节点node的node_mem_map处理
此函数实现如下:
 
static void __ref alloc_node_mem_map(struct pglist_data *pgdat)
{
 unsigned long __maybe_unused start = 0;
 unsigned long __maybe_unused offset = 0;
 /* Skip empty nodes */
 
static void __ref alloc_node_mem_map(struct pglist_data *pgdat)
{
 unsigned long __maybe_unused start = 0;
 unsigned long __maybe_unused offset = 0;
 /* Skip empty nodes 此内存节点内无有效的内存,直接略过*/
 if (!pgdat->node_spanned_pages) 
  return;
 
#ifdef CONFIG_FLAT_NODE_MEM_MAP 只处理平坦型内存
 start = pgdat->node_start_pfn & ~(MAX_ORDER_NR_PAGES - 1);  起始地址必须对其,这个一般按照MB级别对齐即可。
 offset = pgdat->node_start_pfn - start;  看看偏移地址,对齐后地址与真正开始地址之间的偏移大小
 
如果pgdat目前没有设置node_mem_map则对其设置
 /* ia64 gets its own node_mem_map, before this, without bootmem */
 if (!pgdat->node_mem_map) {
  unsigned long size, end;
  struct page *map;
  /*
   * The zone's endpoints aren't required to be MAX_ORDER
   * aligned but the node_mem_map endpoints must be in order
   * for the buddy allocator to function correctly.
   */
  end = pgdat_end_pfn(pgdat);获取节点内结束页帧号pfn
  end = ALIGN(end, MAX_ORDER_NR_PAGES);考虑对齐影响,注意这个需要向前舍入。
  size =  (end - start) * sizeof(struct page);计算需要的数组大小,需要注意end-start是页帧个数,每个页需要一个struct page对象,
所以,这里是乘关系,这样得到整个node内所有以page为单位描述需要占据的内存。
下面分配这个内存大小
  map = alloc_remap(pgdat->node_id, size);
  if (!map) 如果这里分配失败,则通过memblock管理算法分配内存。
    map = memblock_virt_alloc_node_nopanic(size, pgdat->node_id);
 
这里我们可以计算一下,假如4GB内存,则总共有4GB/page_size  个页帧,页大小假如为4KB,则总共有2^20个页,每个页32字节,则这些页占据内存为
2^20  *  32  = 2^25 = 32MB,可以看到,仅仅用于struct page描述的就占据了32MB,32MB/4GB=7.8125%,从占用率来看,这个数据还好。
 
这里对最终的node_mem_map修正偏移位置。一般这个offset为0.
 pgdat->node_mem_map = map + offset;
 }
 
下面是对全局对象mem_map设置,其在当前只有一个node节点时设置。直接来自node 0的node_mem_map值。
#ifndef CONFIG_NEED_MULTIPLE_NODES
 /*
  * With no DISCONTIG, the global mem_map is just set as node 0's
  */
 if (pgdat == NODE_DATA(0)) {
  mem_map = NODE_DATA(0)->node_mem_map;
#if defined(CONFIG_HAVE_MEMBLOCK_NODE_MAP) || defined(CONFIG_FLATMEM)
  if (page_to_pfn(mem_map) != pgdat->node_start_pfn)
   mem_map -= offset;
#endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */
 }
#endif
#endif /* CONFIG_FLAT_NODE_MEM_MAP */
}

GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐