Linux内存:物理内存管理概述
内存中的物理内存管理
概述
一般来说,linux内核一般将处理器的虚拟地址空间划分为2部分。底部比较大的部分用于用户进程,顶部则专用于内核。
在IA-32系统上,地址空间在用户进程和内核之间划分的典型比例是3:1。给出4GB的虚拟地址空间,3GB用于用户空间,而1GB用户内核。
4GB是32位系统上可以寻址的最大内存2的32次方为4GB。
在64位计算机上,由于可用的地址空间非常巨大,因此不需要搞点内存模式。
有2中类型的计算机以不同方法管理内存
- UMA计算机
一致性内存访问,uniform mmeory access,将可用内存以连续方式组织起来。SMP系统中的每个处理器访问各个内存区都是一样快。
- NUMA计算机
非一致内存访问,non-uniform memory access,多处理器计算机。系统的各个CPU都有自己本地内存,可支持特别快速访问。各个处理器通过总线连接起来,以支持对其他CPU的本地内存的访问,比访问本地内存慢些。
(N)UMA模型中的内存组织
内核对一致和非一致内存访问系统使用相同的数据结构,因此针对各种不同形式内存布局,各个算法几乎没有什么差别。在UMA系统上,只使用一个NUMA节点来管理整个系统内存。而内存管理的其他部分则相信他们是在处理一个伪NUMA系统。
首先,内存划分为节点node,用page_date_t表示。每个节点关联到系统的一个处理器。
然后内存进一步细分。比如对可用于(ISA设备的)DMA操作的内存区是有限制。只有前16M适用,还有一个高端内存区域无法映射。在2者之间还有通用的用于“普通”内存区。因此一个节点由3个内存区域组成。
ZONE_DMA
标记适合DMA的区域。该区域的长度依赖于处理器类型。在IA-32计算机上,一般限制是16M。ZONE_DMA32
标记了使用32位地址可寻址、适合DMA的内存区域。显然,只有在64位系统上,2种DMA内存域才有差别。在32位计算机上,该内存是空的,即长度为 0M。在AMD64系统上,该内存的长度可能从0到4GB。ZONE_NORMAL
标记了可直接映射到内核段的普通内存区域。这是在所有体系结构上保证都会存在的唯一内存区域,但无法保证该地址范围对应了实际的物理内存。eg:在AMD64系统有2GB内存,那么所在内存都属于ZONE_DMA32范围,而ZONE_NORMAL则为空。ZONE_HIGHMEM
标记了超出内核段的物理内存。
此外内存标记了一个伪内存ZONE_MOVABLE,防止物理内存碎片的机制中需要使用该内存区域。
各个内存域都关联了一个数组,用来组织属于该内存域的物理内存页(内核称为页帧)。对于每个页帧,都分配了一个struct page 实例以及所需的管理数据。
NODE[NODE pg_data_t] -->|ZONE| B(zone)
B --> dma[ZONE_DMA]
B --> normal[ZONE_NORMAL]
normal -->D[page]
normal -->E[page]
normal -->F[page]
B --> high[ZONE_HIGHMEM]
pg_data_t 表示节点node的基本元素
数据架构
1. 节点管理
pg_data_t 基本元素
<mmzone.h>
typedef struct pglist_data {
struct zone node_zones[MAX_NR_ZONES]; //包含了节点中各内存域的数据结构
struct zonelist node_zonelists[MAX_ZONELISTS];//指定了备用节点以及其内存域的列表
int nr_zones; //节点中不同内存域的数目保存此变量中
//指向 page 实例数组的指针,用于描述结点的所有物理内存页。它包含了结点中所有内存域的页
struct page *node_mem_map;
struct bootmem_data *bdata;
unsigned long node_start_pfn;
unsigned long node_present_pages; /* 物理内存页的总数 */
unsigned long node_spanned_pages; /* 物理内存页的总长度,包含洞在内 */
int node_id;
struct pglist_data *pgdat_next;
wait_queue_head_t kswapd_wait;
struct task_struct *kswapd;
int kswapd_max_order;
} pg_data_t;
2. 内存域
内存使用zone来描述内存域
<mmzone.h>
struct zone {
/*通常由页分配器访问的字段 */
unsigned long pages_min, pages_low, pages_high;
unsigned long lowmem_reserve[MAX_NR_ZONES];
struct per_cpu_pageset pageset[NR_CPUS];
/*
* 不同长度的空闲区域
*/
spinlock_t lock;
struct free_area free_area[MAX_ORDER];
ZONE_PADDING(_pad1_)
/* 通常由页面收回扫描程序访问的字段 */
spinlock_t lru_lock;
struct list_head active_list;
struct list_head inactive_list;
unsigned long nr_scan_active;
unsigned long nr_scan_inactive;
unsigned long pages_scanned; /* 上一次回收以来扫描过的页 */
unsigned long flags; /* 内存域标志,见下文 */
/* 内存域统计量 */
atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS];
int prev_priority;
ZONE_PADDING(_pad2_)
... ...
} ____cacheline_maxaligned_in_smp;
3. 页帧
页帧代表系统内存的最小单位,对内存中的每个页都会创建struct page 的一个实例。内核程序需要注意保持该结构尽可能小,系统内存同样会分解为大量的页。比如IA-32系统标准页程度为4KB,在主内存为384M时,大约共有100 000页。 内存管理的许多部分都是用页。
<mm_types.h>
struct page {
... ...
union {
atomic_t _mapcount; /* 内存管理子系统中映射的页表项计数,
* 用于表示页是否已经映射,还用于限制逆向映射搜索。
*/
unsigned int inuse; /* 用于SLUB分配器:对象的数目 */
};
... ...
}
page 的定义
<mm.h>
struct page {
unsigned long flags; /* 原子标志,有些情况下会异步更新 */
atomic_t _count; /* 使用计数,见下文。 */
union {
atomic_t _mapcount; /* 内存管理子系统中映射的页表项计数,
* 用于表示页是否已经映射,还用于限制逆向映射搜索。
*/
unsigned int inuse; /* 用于SLUB分配器:对象的数目 */
};
union {
struct {
unsigned long private; /* 由映射私有,不透明数据:
* 如果设置了PagePrivate,通常用于buffer_heads;
* 如果设置了PageSwapCache,则用于swp_entry_t;
* 如果设置了PG_buddy,则用于表示伙伴系统中的阶。
*/
struct address_space *mapping; /* 如果最低位为0,则指向inode
* address_space,或为NULL。
* 如果页映射为匿名内存,最低位置位,
* 而且该指针指向anon_vma对象:
* 参见下文的PAGE_MAPPING_ANON。
*/
};
...
struct kmem_cache *slab; /* 用于SLUB分配器:指向slab的指针 */
struct page *first_page; /* 用于复合页的尾页,指向首页 */
};
union {
pgoff_t index; /* 在映射内的偏移量 */
void *freelist; /* SLUB: freelist req. slab lock */
};
struct list_head lru; /* 换出页列表,例如由zone->lru_lock保护的active_list!
*/
#if defined(WANT_PAGE_VIRTUAL)
void *virtual; /* 内核虚拟地址(如果没有映射则为NULL,即高端内存) */
#endif /* WANT_PAGE_VIRTUAL */
};
上面的代码看起来很多,要了解具体的步骤还是参考相应的书籍来看
页表
层次化的页表用于支持大地址空间快速、高效的管理。
页表用于建立用户进程的虚拟地址空间和系统物理内存(内存、页帧)之间的关联。页表用于向每个进程提供一致的虚拟地址空间。应用程序看到的地址空间是一个连续的内存区。该表也将虚拟地址映射到了物理内存,因此支持共享内存实现。
初始化内存管理
内存初始化,在许多CPU上,必须显示设置适用于Linux内核的内存模型。例如在IA32系统上必须先切换到保护模式,然后内核才能检测可用内存和寄存器。在初始化过程中,还必须建立内存管理的数据结构,一起许多其他事务。
start_kernel的代码流程图:
a[start_kernel] --> b[setup_arch]
b-->c[setup_pr_cpu_areas]
c-->d[build_all_zonelists]
d-->e[mem_init]
e-->f[setup_per_cpu_pageset]
- setup_arch 是一个特定于体系结构的设置函数,其中一项任务是负责初始化自举分配器。
- 在SMP系统上, setup_per_cpu_areas 初始化源代码中(使用 per_cpu 宏)定义的静态 per-cpu
变量,这种变量对系统中的每个CPU都有一个独立的副本。此类变量保存在内核二进制映像的
一个独立的段中。 setup_per_cpu_areas 的目的是为系统的各个CPU分别创建一份这些数据
的副本。
在非SMP系统上该函数是一个空操作。 - build_all_zonelists 建立结点和内存域的数据结构(见下文)。
- mem_init 是另一个特定于体系结构的函数,用于停用bootmem分配器并迁移到实际的内存管
理函数,稍后讨论。 - kmem_cache_init 初始化内核内部用于小块内存区的分配器。
- setup_per_cpu_pageset 从上文提到的 struct zone ,为 pageset 数组的第一个数组元素分配
内存。分配第一个数组元素,换句话说,就是意味着为第一个系统处理器分配。系统的所有
内存域都会考虑进来。
物理内存的管理
内核初始化完成后,内存管理的责任就由伙伴系统承担了。
伙伴系统的结构
系统内存中的每个物理内存页(页帧),都对应一个struct page实例。 每个内存域都关联了一个struct zone的实例。
<mmzone.h>
struct zone {
... ...
/*
* 不同长度的空闲区域
*/
struct free_area free_area[MAX_ORDER];
... ...
};
free_area 是一个辅助数据结构
<mmzone.h>
struct free_area {
struct list_head free_list[MIGRATE_TYPES];
unsigned long nr_free;
};
nr_free
自定了当前内存区中空间页块的数目(对0阶内存逐页计算,对1阶内存区计算页对的数目,对2阶内存区计算页对的数据,依次类推)。
free_list
用于连接空闲的链表。
free_area[]
数组中各个元素的所有也解释为阶,用于指定对于链表中的连续内存区包含多少个帧。 第0个链表包含的内存为单页2的零次方为1,第1个链表管理的内存区为2页(2的一次方),依次类推。
slab分配器
内核也经常分配内存。但是用上面伙伴系统分配内存太大了。如果需要一个10个字符的字符串分配空间,分配一个4KB或者更多空间的页面,浪费空间。解决方案就是将页拆分为更小的单位,可以容纳大量的小对象。
slab不仅能作为小内存的分配器,也可以作为一种缓存使用,主要是针对经常分配并释放的对象。通过建立slab缓存,内核就能储备一些对象,供后续使用。
Linux内存:物理内存管理概述的更多相关文章
- Linux内存描述之概述--Linux内存管理(一)
1 前景回顾 1.1 UMA和NUMA两种模型 共享存储型多处理机有两种模型 均匀存储器存取(Uniform-Memory-Access,简称UMA)模型 将可用内存以连续方式组织起来, 非均匀存储器 ...
- linux 内存地址空间管理 mm_struct
http://blog.csdn.net/yusiguyuan/article/details/39520933 Linux对于内存的管理涉及到非常多的方面,这篇文章首先从对进程虚拟地址空间的管理说起 ...
- Linux软件安装管理概述
介绍如何在Linux字符界面下安装软件 课程大纲: 一.软件包管理简介 二.rpm命令管理 三.yum在线管理 四.源码包管理 五.脚本安装包
- LInux中的物理内存管理
2017-02-23 一.伙伴系统 LInux下用伙伴系统管理物理内存页,伙伴系统得益于其良好的算法,一定程度上可以避免外部碎片为何这么说?先回顾下Linux下虚拟地址空间的分布. 在X86架构下,系 ...
- Linux内存管理的基本框架⭐⭐
Linux内核的映射机制设计成三层,在页面目录和页面表中间增设了一层“中间目录”.在代码中,页面目录称为PGD,中间目录称为PMD,而页面表称为PT.PT中的表项称为PTE,PTE是“Page Tab ...
- [转帖]Linux分页机制之概述--Linux内存管理(六)
Linux分页机制之概述--Linux内存管理(六) 2016年09月01日 19:46:08 JeanCheng 阅读数:5491 标签: linuxkernel内存管理分页架构更多 个人分类: ┈ ...
- 启动期间的内存管理之初始化过程概述----Linux内存管理(九)
在内存管理的上下文中, 初始化(initialization)可以有多种含义. 在许多CPU上, 必须显式设置适用于Linux内核的内存模型. 例如在x86_32上需要切换到保护模式, 然后内核才能检 ...
- Linux内存管理 (1)物理内存初始化
专题:Linux内存管理专题 关键词:用户内核空间划分.Node/Zone/Page.memblock.PGD/PUD/PMD/PTE.lowmem/highmem.ZONE_DMA/ZONE_NOR ...
- 非常好的博客!!!linux内存管理概述【转】
转自:http://blog.csdn.net/bullbat/article/details/7166140 inux内存管理建立在基本的分页机制基础上,在linux内核中RAM的某些部分将会永久的 ...
随机推荐
- Codeforces 999
A /*Huyyt*/ #include<bits/stdc++.h> #define mem(a,b) memset(a,b,sizeof(a)) using namespace std ...
- P1879 [USACO06NOV]玉米田Corn Fields[轮廓线DP]
状压暴力显然可做.但是数据出的再大一点就要稳T了.理论$O(n4^m)$,只不过实际跑不满. 考虑用轮廓线DP,设$f(i,j,S)$为处理到$(i,j)$时候(这格还不确定)的轮廓线为$S$的情况( ...
- fedora29 安装mongodb 4.0,6问题记录
如果运行mongod命令时提示 无加载共享库libcrypto.so.10,那就到页面下载http://www.rpmfind.net/linux/rpm2html/search.php?query= ...
- MHA配置
1,背景 MHA的目的在于维持MySQL Replication中Master库的高可用性,其最大特点是可以修复多个Slave之间的差异日志,最终使所有Slave保持数据一致,然后从中选择一个充当新的 ...
- Open Cascade 转化为OpenSceneGraph中的Mesh
#include <osgDB/ReadFile> #include <osgViewer/Viewer> #include <osgGA/StateSetManipul ...
- JavaWeb_(SSH论坛)_四、页面显示
基于SSH框架的小型论坛项目 一.项目入门 传送门 二.框架整合 传送门 三.用户模块 传送门 四.页面显示 传送门 五.帖子模块 传送门 六.点赞模块 传送门 七.辅助模块 传送门 帖子表与回复表 ...
- 如何将项目托管到Github上
将本地项目放到GitHub上托管并展示 传送门 利用Github Pages展示自己的项目 传送门 git Please tell me who you are解决方法 传送门 git config ...
- JS框架_(AJAX)检测ip和地区
百度云盘 传送门 密码:l94p 实现效果: <!DOCTYPE html> <html> <head> <meta charset="utf-8 ...
- centOS7安装docker遇到 [Errno 14] curl#35 - "TCP connection reset by peer问题解决
---------------------------------------------------------------------------------------------------- ...
- SQL中模糊查询的模式匹配
SQL模糊查询的语法为: “Select column FROM table Where column LIKE 'pattern'”. SQL提供了四种匹配模式: 1. % 表示任意0个或多个字符. ...