文章目录
前言
衔接上文,之前我们说到了Linux的一些基础概念以及Linux的进程与线程,这次我们来看看Linux操作系统的内核结构中的内存管理,I/O管理以及文件系统,本笔记只有上下两篇哦,看完你也能轻松掌握Linux操作系统。一、Linux 内存管理
众所周知,Linux采用虚拟内存管理技术,每个进程都有独立的进程地址空间。这是Linux内存管理的基础,所以我们先讲解一下虚拟内存技术。虚拟内存技术是基于交换技术(swap)的,只不过交换的是页或者段。
1.虚拟内存
虚拟内存技术的好处:
- 扩大内存(主要催生虚拟内存原因)
- 安全性提高(不直接访问物理内存)
- 易于开发(每个进程拥有独立的用户空间)
虚拟内存技术就是只装入程序的一部分,就开始运行整个程序。那么这样内存压力就会变小,能够运行大内存需求的软件。
虚拟内存的实现原理是:当进程要求运行的时,不是将他的全部信息装入内存,而是将其一部分先装入内存,另一部分暂时留在外存,进程在运行过程中,要使用信息不在内存时,发生中断,由操作系统将他们调如内存,以保证进程的正常运行。但是呢,从进程角度来说,会认为它拥有连续可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。
总结一下,虚拟内存实现可以总结为三步: - 先加载进程的一部分数据
- 需要不在内存的数据,发生中断(缺页中断/缺段中断)
- 将数据调入内存
在Linux内部的地址的映射过程为逻辑地址–>线性地址–>物理地址,逻辑地址经段机制转化成线性地址;线性地址又经过页机制转化为物理地址。简单的讲就是,在虚拟内存管理的时候,实质上的管理的是一段一段的(逻辑段),这一段一段的内存组和起来就是我们常规理解的线形地址,而在这一段一段的虚拟内存再使用页机制转化到物理内存上
Note:我们要知道,页是信息的物理单位,分页是为实现离散分配方式,以消减内存的外零头,提高内存的利用率。段则是信息的逻辑单位,它含有一组其意义相对完整的信息。分段的目的是为了能更好地满足用户的需要。这也是段和页的区别。
页机制
Linux中内存管理单元(MMU,把虚拟地址转换为物理地址的硬件设备)是以页为单位处理,我们把虚拟出来的内存分成等大的内存块,叫做页(page)
(虚拟内存空间的顺序划分),把物理内存分成同等大小的内存块,叫做页框(pageframe)
(对物理内存按顺序等大小的划分)
页面置换算法
首先检测是否有空闲的页框,如果有,那么将从交换分区调入的页装配到空闲页框中(swap in)。如果没有空闲页框,那系统按预定的置换策略(页面置换算法)自动选择一个或一些在内存的页面,如果这个或者这些页面为dirty,那么就将其换到(swap out)交换分区,空出页框了,就可以安置所需的页(swap in)
但是,在页面置换算法上,Linux 并没有采取这一种常规做法,Linux有一个守护进程kswapd
,比较每个内存区域的高低水位来检测是否有足够的空闲页面来使用,每次运行时,仅有一个确定数量的页面被回收。
Linux采用的页面置换算法是一种改进的LRU算法–最近最少使用(LRU)页面的衰老算法,维护两组标记:活动/非活动和是否被引用。第一轮扫描清除引用位,如果第二轮运行确定被引用,就提升到一个不太可能回收的状态,否则将该页面移动到一个更可能被回收的状态。
处于非活动列表的页面,自从上次检查未被引用过,因而是移除的最佳选择。被引用但不活跃的页面同样会被考虑回收,是因为一些页面是守护进程访问的,可能很长时间不再使用。转换状态如下:
另外,内存管理还有一个守护进程pdflush
,会定期醒来,写回脏页面;或者可用内存下降到一定水平后被内核唤醒。
MMU
内存管理单元(Memory Management Unit),MMU会将逻辑地址映射为物理地址,其实MMU虚实地址映射就是寻找物理页帧的过程
既然所有发往内存的地址信号都要经过MMU处理,那么MMU就可以以很小的代价承担更大的责任,比如内存保护。可以在PTE条目中预留出几个比特,用于设置访问权限的属性,如禁止访问、可读、可写和可执行等。
物理内存映射
Linux 采用的是三级页表。随着64位CPU,比如X86_64,出现四级页表页开始诞生,原理相同,这里看一下Linux的三级页表。
页全局目录 (Page Global Directory,即PGD) :全局字典,指向中间页目录。
页中间目录( Page Middle Directory,即PMD) :中间字典,也可以理解为二级目录,指向PTE中的表项。
页表 (Page Table,即PTE):指向物理页面 。
偏移量(Page Offset):即页内偏移。
2.进程内存分布
每一个进程都有4G的线性虚拟地址空间,且内核空间是由内核负责映射,不会跟着进程变化;内核空间地址有自己对应的页表,用户进程各自有不同的页表。可以理解为每个普通进程都有自己的用户空间,但是内核空间被所有普通进程所共享(每个进程虚拟空间的3G~4G部分是相同的 )。另外,用户态进程只能访问0-3G,但是内核态进程既可以访问0-3G,也可以访问3G-4G地址空间。
下面来看看进程在虚拟内存中的分布情况:
- 内核态
- 固定映射区(Fixing Mapping Region):该区域和4G的顶端只有4k的隔离带,其每个地址项都服务于特定的用途,如ACPI_BASE等。
- 永久内存映射区(PKMap Region):该区域可访问高端内存。访问方法是使用alloc_page(_GFP_HIGHMEM)分配高端内存页或者使用kmap函数将分配到的高端内存映射到该区域。
- 动态内存映射区(Vmalloc Region):该区域由内核函数vmalloc来分配,特点是:
线性空间连续,但是对应的物理空间不一定连续
。vmalloc分配的线性地址所对应的物理页可能处于低端内存,也可能处于高端内存。 - 直接映射区(Direct Memory Region):线性空间中从3G开始最大896M的区间,为直接内存映射区,该区域的线性地址和物理地址存在线性转换关系:线性地址=3G+物理地址。
- 用户态
- 栈:栈是用户