文章目录
- 交换分区
- 页与页框(页帧)
- 交换分区与内存之间的交换
- 操作系统如何管理内存
- 物理地址转换页号与页内偏移量
- 内存管理,文件系统与文件管理之间的联系
交换分区
在Linux的安装过程中,用户将会被提示创建一个交换分区;
这是一个特殊的分区,其大小可以由用户根据系统内存需求和推荐进行决定;
若是存在交换分区,通常在Linux中交换分区在文件系统当中并不会挂载,因此它不会在默认的文件浏览器中被显示未一个可访问的驱动器或者是目录;
一般来说一个分区中应当存在一个文件系统,而交换分区虽然被称为分区但其并不存在文件系统;
这块空间虽然在磁盘空间中,但实际上这块空间是交由内存管理所运用;
-
交换分区与文件系统的关系:
-
独立性:
交换分区通常不包含一个文件系统,其并不是用来存储文件或者目录结构的;
它将直接由操作系统进行管理,用于存放被换出的内存页;
-
专用性:
由于交换分区是专门用于内存管理的,因此它与用于存储文件的常规文件系统分区有着本质的区别;
操作系统将直接在交换分区上操作内存页而不是文件或文件系统结构;
-
-
内存管理运用:
-
内存扩展
交换分区相当于是物理内存的一个拓展,提供了一种机制,允许系统使用硬盘空间来模拟额外的RAM从而增加了可用的内存资源;
-
内存释放
当系统的物理内存不足时操作系统可以将不活跃的内存页移交到交换分区并释放内存空间给其他更需要紧急处理的程序或是数据;
-
页与页框(页帧)
在内存管理中存在两个概念,分别为页与页框(页帧);
页是进程地址空间中的最小单位,一般为4kb大小;
而页框(页帧)是物理内存当中的最小单位,其大小等于页的大小;
页通过页表映射至不同页框(页帧)中以实行内存管理;
-
页(Page)
-
定义:
页是虚拟内存中的一个固定大小的块,时进程地址空间中的最小单位;
-
大小:
通常为4kb,但在某些系统重也可以是2MB或者更大(大页或巨页);
-
作用:
页用于将进程地址空间中的虚拟地址划分为若干个固定大小的块从而方便对其进行管理与映射至物理内存;
-
-
页框/页帧(Page Frame)
-
定义:
页框或页帧是物理内存中的一个固定大小的块,其大小与页的大小相同;
-
大小:
通常为4kb,与页的大小相同;
-
作用:
页框用于存储页的内容;
-
页框/页帧的大小可以进行修改,但是其大小的修改只能重新选择操作系统的编译选项对操作系统进行重新编译才能生成;
虚拟内存中的页通过页表映射到物理内存中的页框;
页表记录了每个页对应的页框的信息;
当CPU访问一个虚拟地址时候,内存管理单元MMU将通过页表将虚拟地址转化为物理地址从而方位物理内存中的数据;
其中页表中存储的数据被称为页表项;
页表项是页表中的基本单元,每一个页表项对应一个页,记录了该页在物理内存中的映射信息(页框/页帧);
同通常地址转换过程如下:
-
虚拟地址
虚拟地址由两部分组成,页号(Page Number)和页内偏移量(Offset);
-
页表查找
页号用于索引页表,并找到对应的页表项;
-
物理地址
从页表项中获取页框号,然后与页内偏移量组合形成物理地址;
-
内存访问
CPU使用物理地址访问物理内存中的数据;
当需要访问一个被交换到磁盘上的页面时将会触发缺页中断;
操作系统会将所需的页面从交换分区中换回物理内存,并重新更新页表以反映新的映射关系从而结局缺页中断的问题;
交换分区与内存之间的交换
当存在交换分区且物理内存不足等情况后,操作系统将会将部分没有必要的 页框/页帧 换出至磁盘中的交换分区中,这种交换被称为页面置换;
这是通过页面置换的算法实现的;
通常页面置换的算法包括:
-
最近最少使用
操作系统将选择最近最少使用的页面进行置换;
-
先进先出
操作系统将选择最早加载到内存中的页进行置换;
-
最不常用
操作系统将选择使用频率最低的页面进行置换;
通常被换出的大小为一个页框/页帧的大小,由于局部性原理,置换的页面可能是连续的,所以对于资源的浪费上一般只有最后一个页才会被浪费;
同时由于空间局部性原理,当在访问一个页时将会有很大的概率去访问该页的上下文,所以当在进行交换时将会有一个预加载机制,固定大小可以有效的进行这个预加载机制;
同时交换大小的固定可以减少内部碎片;
操作系统如何管理内存
在计算机当中操作系统可以直接看到物理内存并直接或间接对物理内存进行内存管理;
操作系统将把物理内存看做是若干个"页框/页帧";
且将通过 “先描述,再组织” 的方式对物理内存进行管理;
在操作系统内存中存在名为struct page
的结构体;
这个结构体用于表示无力内存中的一个"页框/页帧",每个物理"页框/页帧"都有一个对应的 struct page
结构体实例,操作系统内核将通过这些结构体来管理物理内存;
其主要的字段如下:
-
flags
该字段用于存储页的状态标志,如是否被锁定,是否为脏页等;
-
count
引用计数,表示该页框被引用的次数;
如在进行子进程的创建时,其子进程将为父进程的一份拷贝,其进程地址空间中所映射的物理内存在未进行写入操作的状态下为同一个物理内存;
而该引用计数即为维护页框被引用的次数;
-
mapping
指向该页所属的地址空间;
-
private
用于存储与页框相关的私有数据;
-
virtual
当页框被页映射时该字段将存储页框的虚拟地址;
struct page {
unsigned long flags; // 页的状态标志
atomic_t count; // 引用计数
struct address_space *mapping; // 地址空间指针
pgoff_t index; // 页的索引
void *private; // 私有数据
void *virtual; // 虚拟地址
};
以4GB
为例,该内存当中将会有
4
×
1024
×
1024
×
1024
bytes
4
×
1024
bytes/page
=
1048576
pages
\frac{4 \times 1024 \times 1024 \times 1024 \text{ bytes}}{4 \times 1024 \text{ bytes/page}} = 1048576 \text{ pages}
4×1024 bytes/page4×1024×1024×1024 bytes=1048576 pages
个这样的结构体;
而这些结构体将会以数组的方式进行管理,struct page mem_array[1048576]
;
而这个数组中每一个数组下标即对应着一个页框的 页号 ;
- 例如
-
mem_array[0]
对应第一个物理页框; -
mem_array[1]
对应第二个物理页框; - 以此类推,
mem_array[1048575]
对应最后一个物理页框;
-
在32位机器中,页内偏移量占用低12
位,页号占用高20
位;
一般情况下物理地址的计算如下:
- 物理地址 = 页号 * 页大小 + 页内偏移量
假设页的大小为4kb
,页号为i
,页内偏移量为offset
,则物理地址为:
- 物理地址 = i * 212 + offset
因为这个结构体是存在于页框当中,而页框的大小仅只有4kb
;
所以对应的结构体并不会太大(避免过多占用内存),通常以union
的形式定义;
物理地址转换页号与页内偏移量
在32
位系统中,物理地址为32
位;
假设页的大小为4kb
即 212 字节;
其中页号占用高20
位,页内偏移量占用低12
位;
- 提取页号
- 掩码:
0xFFFF F000
- 操作: 物理地址 &
0xFFFF F000
- 结果: 保留高
20
位,将低12
位清零;
- 掩码:
- 提取页内偏移量
- 掩码:
0x0000 0FFF
- 操作: 物理地址 &
0x0000 0FFF
- 结果: 保留低
12
位,将高20
位清零;
- 掩码:
假设物理地址为0x12345678
;
其二进制表示:0001 0010 0011 0100 0101 0110 0111 1000
;
-
高20位(页号)
高20位:
0001 0010 0011 0100 0101
十六进制表示:0x12345
-
低12位(页内偏移量)
低12位:
0110 0111 1000
十六进制表示:0x678
当需要访问一个内存时只需要先找到这个4kb
对应的page
即可以找到对应的物理页框;
而实际上所有方位内存的动作都可以看做是访问内存Page
数组;
内存管理,文件系统与文件管理之间的联系
当操作系统启动时将会进行预加载;
在文件系统中的预加载的内容一般为文件系统中的关于SuperBlock
,GroupDescriptorTable
,BlockBitmap
,InodeBitmap
等属性信息从而方便操作系统内核对其进行管理;
-
属性
当一个进程需要打开一个文件时,操作系统将会为这个打开的文件在进程的
task_struct
结构体中维护一个file_struct
结构体,其中这个结构体中保存了一个struct file*fd_array[]
结构体用于指向各个struct file
文件结构体;其中
file* fd_array[]
结构体的下标即为文件描述符;当打开一个文件时即为需要去访问该文件的信息,在
struct file
结构体中存储的信息只为少量的信息;详细信息一般被存储在文件的
Inode
中;而操作系统将会通过物理内存中的
InodeBitmap
,InodeTable
中依次去寻找其对应的Inode;当找到对应的Inode后操作系统内核将为这个打开的文件维护一个
struct inode
结构体并将Inode中的信息加载至该结构体当中从而能够建立文件与内核之间的联系;struct inode { umode_t i_mode; // 文件类型和权限 unsigned long i_ino; // inode 号 atomic_t i_count; // 引用计数 struct file_operations *i_fop; // 文件操作函数指针 struct super_block *i_sb; // 指向超级块的指针 struct address_space *i_mapping; // 地址空间指针 loff_t i_size; // 文件大小 struct timespec i_atime; // 最后访问时间 struct timespec i_mtime; // 最后修改时间 struct timespec i_ctime; // inode 最后更改时间 // 其他字段... };
-
内容
同样的在
struct file
结构体中有一个指针,该指针指向了一个名为struct address_space
的结构体;struct radix_tree_root { void *rnode; // 基数树根节点指针 // 其他字段... };
在这个结构体中将会维护一棵名为
radix_tree_root
树,这是一棵结构为基数树的树;而其中这棵树的每个节点即指向了一个
strcut page
的结构体;struct page { unsigned long flags; // 页的状态标志 atomic_t count; // 引用计数 struct address_space *mapping; // 地址空间指针 pgoff_t index; // 页的索引 void *private; // 私有数据 void *virtual; // 虚拟地址 };