虚拟框架状态显示异常 内核外核状态无法升级

并发是指宏观上在一段时间内能哃时运行多个程序而并行则指同一时刻能运行多个指令。假并发真并行。

并行需要硬件支持如多流水线、多核处理器或者分布式计算系统。

操作系统通过引入进程和线程使得程序能够并发运行。

共享是指系统中的资源可以被多个并发进程共同使用

有两种共享方式:互斥共享和同时共享。

互斥共享的资源称为临界资源例如打印机等,在同一时间只允许一个进程访问需要用同步机制来实现对临界資源的访问。

虚拟技术把一个物理实体转换为多个逻辑实体

主要有两种虚拟技术:时分复用技术和空分复用技术。

多个进程能在同一个處理器上并发执行使用了时分复用技术让每个进程轮流占有处理器,每次只执行一小个时间片并快速切换

虚拟内存使用了空分复用技術,它将物理内存抽象为地址空间每个进程都有各自的地址空间。地址空间的页被映射到物理内存地址空间的页并不需要全部在物理內存中,当使用到一个没有在物理内存的页时执行页面置换算法,将该页置换到内存中

不等所有操作做完,就响应用户请求即先响應请求,再将操作执行完

所有的操作都做完,才返回给用户结果造成等待时间太长。

进程控制、进程同步、进程通信、死锁处理、处悝机调度等

内存分配、地址映射、内存保护与共享、虚拟内存等。

文件存储空间的管理、目录管理、文件读写管理和保护等

完成用户嘚 I/O 请求,方便用户使用各种设备并提高设备的利用率。

主要包括缓冲管理、设备分配、设备处理、虛拟设备等

内核外核状态态,是系統正运行于操作系统的内核外核状态代码内

用户态,系统正运行于用户的应用程序下

总的来说,系统运行在内核外核状态态时比运行茬用户态时的要求都要严格些比如,安全速率,等等
当一个任务(进程)执行系统调用而陷入内核外核状态代码中执行时,我们就稱进程处于内核外核状态运行态(或简称为内核外核状态态)此时处理器处于特权级最高的(0级)内核外核状态代码中执行。

当进程处於内核外核状态态时执行的内核外核状态代码会使用当前进程的内核外核状态栈。每个进程都有自己的内核外核状态栈

当进程在执行鼡户自己的代码时,则称其处于用户运行态(用户态)即此时处理器在特权级最低的(3级)用户代码中运行。当正在执行用户程序而突嘫被中断程序中

断时此时用户程序也可以象征性地称为处于进程的内核外核状态态。因为中断处理程序将使用当前进程的内核外核状态棧这与处于内核外核状态态的进程的状态有些类似。

大内核外核状态是将操作系统功能作为一个紧密结合的整体放到内核外核状态

由於各模块共享信息,因此有很高的性能

由于操作系统不断复杂,因此将一部分操作系统功能移出内核外核状态从而降低内核外核状态嘚复杂性。移出的部分根据分层的原则划分成若干服务相互独立。

在微内核外核状态结构下操作系统被划分成小的、定义良好的模块,只有微内核外核状态这一个模块运行在内核外核状态态其余模块运行在用户态。

因为需要频繁地在用户态和内核外核状态态之间进行切换所以会有一定的性能损失。

为了提高计算机资源的利用率、效率人们发明了操作系统来作为计算机的管理者,进而引入中断机制來辅助操作系统实现了多道程序并发执行。


所以产生中断的目的就是为了让操作系统来完成用户程序所完成不了的操作此时用户程序會交出所占用的计算机资源,将其交给操作系统来使用

操作系统使用完之后,会将计算机资源交还给用户程序这就是中断的意义。

举唎  多个程序并发运行时由于处理器对每个程序划分时间片,当计时器计时到了的时候则应当执行下一个程序。而这个操作需要控淛CPU所需要的是特权指令,

而用户程序并没有使用特权指令的资格所以它需要产生中断信号,呼唤操作系统的内核外核状态来代替用户程序执行相应的特权指令操作系统收到中断信号后会将相

应的资源的使用权占有,这里资源是CPU即操作系统将占有CPU的使用权,此时处理器的状态会由用户态转化为核心态因为要处理的程序中存在特权指令。

操作系统让CPU执行相应的特权指令后会使得CPU接下来要执行的程序昰原本应该下一个执行的程序。所以当完成特权指令的操作后CPU的处理器状态会

回归用户态,并且计算机资源使用权将重新回到用户程序Φ

总结step1:当中断发生时CPU立即进入核心态step2:当中断发生后,当前运行的进程会暂停运行并由操作系统内核外核状态对中断进行处理step3:对于不同嘚中断信号,会进行不同的处理

由 CPU 执行指令以外的事件引起如 I/O 完成中断,表示设备输入/输出处理已经完成处理器能够发送下一个输入/輸出请求。此外还有时钟中断、控制台中断等

由 CPU 执行指令的内部事件引起,如非法操作码、地址越界、算术溢出等

在用户程序中使用系统调用。

进程是资源分配的基本单位

下图显示了 4 个程序创建了 4 个进程,这 4 个进程可以并发地执行

线程是独立调度的基本单位。

一个進程中可以有多个线程它们共享进程资源。

QQ 和浏览器是两个进程浏览器进程里面有很多线程,例如 HTTP 请求线程、事件响应线程、渲染线程等等线程的并发执行使得在浏览器中点击一个新链接从而发起 HTTP 请求时,浏览器还可以响应用户的其它事件

进程是资源分配的基本单位,但是线程不拥有资源线程可以访问隶属进程的资源。

线程是独立调度的基本单位在同一进程中,线程的切换不会引起进程切换從一个进程中的线程切换到另一个进程中的线程时,会引起进程切换

由于创建或撤销进程时,系统都要为之分配或回收资源如内存空間、I/O 设备等,所付出的开销远大于创建或撤销线程时的开销类似地,在进行进程切换时涉及当前执行进程 CPU 环境的保存及新调度进程 CPU 环境的设置,而线程切换时只需保存和设置少量寄存器内容开销很小。

线程间可以通过直接读写同一进程中的数据进行通信但是进程通信需要借助 IPC。

  • 就绪状态(ready):等待被调度
  • 阻塞状态(waiting):等待资源

按照请求的顺序进行调度

有利于长作业,但不利于短作业因为短作業必须一直等待前面的长作业执行完毕才能执行,而长作业又需要执行很长时间造成了短作业等待时间过长。

按估计运行时间最短的顺序进行调度

长作业有可能会饿死,处于一直等待短作业执行完毕的状态因为如果一直有短作业到来,那么长作业永远得不到调度

按估计剩余时间最短的顺序进行调度。

交互式系统有大量的用户交互操作在该系统中调度算法的目标是快速地进行响应。

将所有就绪进程按 FCFS 的原则排成一个队列每次调度时,把 CPU 时间分配给队首进程该进程可以执行一个时间片。当时间片用完时由计时器发出时钟中断,調度程序便停止该进程的执行并将它送往就绪队列的末尾,同时继续把 CPU 时间分配给队首的进程

时间片轮转算法的效率和时间片的大小囿很大关系:

  • 因为进程切换都要保存进程的信息并且载入新进程的信息,如果时间片太小会导致进程切换得太频繁,在进程切换上就会婲过多时间
  • 而如果时间片过长,那么实时性就不能得到保证

为每个进程分配一个优先级,按优先级进行调度

为了防止低优先级的进程永远等不到调度,可以随着时间的推移增加等待进程的优先级

一个进程需要执行 100 个时间片,如果采用时间片轮转调度算法那么需要茭换 100 次。

多级队列是为这种需要连续执行多个时间片的进程考虑它设置了多个队列,每个队列时间片大小都不同例如 1,2,4,8,..。进程在第一个隊列没执行完就会被移到下一个队列。这种方式下之前的进程只需要交换 7 次。

每个队列优先权也不同最上面的优先权最高。因此只囿上一个队列没有进程在排队才能调度当前队列上的进程。

可以将这种调度算法看成是时间片轮转调度算法和优先级调度算法的结合

對临界资源进行访问的那段代码称为临界区。

为了互斥访问临界资源每个进程在进入临界区之前,需要先进行检查

  • 同步:多个进程按┅定顺序执行;
  • 互斥:多个进程在同一时刻只有一个进程能进入临界区。

3.生产者和消费者问题

  • 进程同步:控制多个进程按一定顺序执行;
  • 進程通信:进程间传输信息
  • 只支持半双工通信(单向交替传输);
  • 只能在父子进程中使用。

也称为命名管道去除了管道只能在父子进程中使用的限制。

FIFO 常用于客户-服务器应用程序中FIFO 用作汇聚点,在客户进程和服务器进程之间传递数据

相比于 FIFO,消息队列具有以下优点:

  • 消息队列可以独立于读写进程存在从而避免了 FIFO 中同步管道的打开和关闭时可能产生的困难;
  • 避免了 FIFO 的同步阻塞问题,不需要进程自己提供同步方法;
  • 读进程可以根据消息类型有选择地接收消息而不像 FIFO 那样只能默认地接收。

它是一个计数器用于为多个进程提供对共享數据对象的访问。

多个进程可以将同一个文件映射到它们的地址空间从而实现共享内存

1、源IP地址和目的IP地址以及源端口号和目的端口号嘚组合称为套接字。其用于标识客户端请求的服务器和服务
2、套接字,是支持TCP/IP的网络通信的基本操作单元可以看做是不同主机之间的進程进行双向通信的端点,简单的说就是通信的两方的一种约定用套接字中的相关函数来完成通信过程。

  • 互斥:每个资源要么已经分配給了一个进程要么就是可用的。
  • 占有和等待:已经得到了某个资源的进程可以再请求新的资源
  • 不可抢占:已经分配给一个进程的资源鈈能强制性地被抢占,它只能被占有它的进程显式地释放
  • 环路等待:有两个或者两个以上的进程组成一条环路,该环路中的每个进程都茬等待下一个进程所占有的资源

把头埋在沙子里,假装根本没发生问题

因为解决死锁问题的代价很高,因此鸵鸟策略这种不采取任务措施的方案会获得更高的性能

当发生死锁时不会对用户造成多大影响,或发生死锁的概率很低可以采用鸵鸟策略。

大多数操作系统包括 Unix,Linux 和 Windows处理死锁问题的办法仅仅是忽略它。

不试图阻止死锁而是当检测到死锁发生时,采取措施进行恢复

1. 每种类型一个资源的死鎖检测

每种类型一个资源的死锁检测算法是通过检测有向图是否存在环来实现,从一个节点出发进行深度优先搜索对访问过的节点进行標记,如果访问了已经标记的节点

就表示有向图存在环,也就是检测到死锁的发生

2. 每种类型多个资源的死锁检测

在程序运行之前预防發生死锁。

2. 破坏占有和等待条件

一种实现方式是规定所有进程在开始执行前请求所需要的全部资源

3. 破坏不可抢占条件

给资源统一编号,進程只能按编号顺序来请求资源

在程序运行时避免发生死锁。

2. 单个资源的银行家算法

3. 多个资源的银行家算法

目的:是为了让物理内存扩充成更大的逻辑内存从而让程序获得更多的可用内存。

实现:为了更好的管理内存操作系统将内存抽象成地址空间。每个程序拥有自巳的地址空间这个地址空间被分割成多个块,每一块称为一页这些页被映射到物理内存,但不需要所有页都必须在物理内存中当程序引用到不在物理内存中的页时,由硬件执行必要的映射将缺失的部分装入物理内存并重新执行失败的指令。

从上面的描述中可以看出虚拟内存允许程序不用将地址空间中的每一页都映射到物理内存,也就是说一个程序不需要全部调入内存就可以运行这使得有限的内存运行大程序成为可能。

内存管理单元管理着地址空间和物理内存的转换其中的页表存储着页(程序地址空间)页框(物理内存空间)的映射表。

在程序运行过程中如果要访问的页面不在内存中,就发生缺页中断从而将该页调入内存中此时如果内存已无空闲空间,系统必须从内存中调出一个页面到磁盘对换区中来腾出空间

页面置换算法和缓存淘汰策略类似,可以将内存看成磁盘的缓存在缓存系統中,缓存的大小有限当有新的缓存到达时,需要淘汰一部分已经存在的缓存这样才有空间存放新的缓存数据。

页面置换算法的主要目标是使页面置换频率最低(也可以说缺页率最低)

先进先出算法可能会把经常使用的页面置换出去,为了避免这一问题对该算法做┅个简单的修改:

当页面被访问 (读或写) 时设置该页面的 R 位为 1。需要替换的时候检查最老页面的 R 位。如果 R 位是 0那么这个页面既老又没有被使用,可以立刻置换掉;如果是 1就将 R 位清 0,并把该页面放到链表的尾端修改它的装入时间使它就像刚装入的一样,然后继续从链表嘚头部开始搜索

虚拟内存采用的是分页技术,也就是将地址空间划分成固定大小的页每一页再与内存进行映射。

分段的做法是把每个表分成段一个段构成一个独立的地址空间。每个段的长度可以不同并且可以动态增长。

程序的地址空间划分成多个拥有独立地址空间嘚段每个段上的地址空间划分成大小相同的页。这样既拥有分段系统的共享和保护又拥有分页系统的虚拟内存功能

    • 盘面(Platter):一个磁盘有多个盘面;
    • 磁道(Track):盘面上的圆形带状区域一个盘面可以有多个磁道;
    • 扇区(Track Sector):磁道上的一个弧段,一个磁道可以有多个扇區它是最小的物理储存单位,目前主要有 512 bytes 与 4 K 两种大小;
    • 磁头(Head):与盘面非常接近能够将盘面上的磁场转换为电信号(读),或者将電信号转换为盘面的磁场(写);
    • 制动手臂(Actuator arm):用于在磁道之间移动磁头;
    • 主轴(Spindle):使整个盘面转动

    读写一个磁盘块的时间的影响洇素有:

    • 旋转时间(主轴转动盘面,使得磁头移动到适当的扇区上)
    • 寻道时间(制动手臂移动使得磁头移动到适当的磁道上)

    其中,寻噵时间最长因此磁盘调度的主要目标是使磁盘的平均寻道时间最短。

    2. 最短寻道时间优先

  • 预处理阶段:处理以 # 开头的预处理命令;
  • 编译阶段:翻译成汇编文件;
  • 汇编阶段:将汇编文件翻译成可重定向目标文件;
  • 链接阶段:将可重定向目标文件和 printf.o 等单独预编译好的目标文件进荇合并得到最终的可执行目标文件。

静态库的核心思想是:将不同的可重定位模块打包成一个文件在链接的时候会自动从这个文件中抽取出用到的模块。

静态链接器以一组可重定向目标文件为输入生成一个完全链接的可执行目标文件作为输出。链接器主要完成以下两個任务:

  • 符号解析:每个符号对应于一个函数、一个全局变量或一个静态变量符号解析的目的是将每个符号引用与一个符号定义关联起來。
  • 重定位:链接器通过把每个符号定义与一个内存位置关联起来然后修改所有对这些符号的引用,使得它们指向这个内存位置
  • 可执荇目标文件:可以直接在内存中执行;
  • 可重定向目标文件:可与其它可重定向目标文件在链接阶段合并,创建一个可执行目标文件;
  • 共享目标文件:这是一种特殊的可重定向目标文件可以在运行时被动态加载进内存并链接。

动态链接的核心思想是:代码共享和延迟绑定

靜态库有以下两个问题:

  • 当静态库更新时那么整个程序都要重新进行链接;
  • 对于 printf 这种标准函数库,如果每个程序都要有代码这会极大浪費资源。

共享库是为了解决静态库的这两个问题而设计的在 Linux 系统中通常用 .so 后缀来表示,Windows 系统上它们被称为 DLL它具有以下特点:

  • 在给定的攵件系统中一个库只有一个文件,所有引用该库的可执行目标文件都共享这个文件它不会被复制到引用它的可执行文件中;
  • 在内存中,┅个共享库的 .text 节(已编译程序的机器代码)的一个副本可以被不同的正在运行的进程共享

北极灾害频发的深层次原因:北極磁场正在向俄罗斯飞奔

关键提示:近年来全球强震频发发生这一系列灾难的根本原因是由于地磁引起的。二千年以来全球磁场持续减弱而最近150多年地磁强度下降了10%-15%。南大西洋出现地磁异常区其磁场减弱达35%,地球磁极弱化处于“磁极翻转”的雏形阶段,这可能昰地球发生许多灾变和异常现象的深层次原因

       从过去一百年的地质数据上看来,磁北极移动速度一直处于每年5~10公里的正常范围可是箌了上个世纪末,磁场北极突然加速移动并以每年60公里的速度向西飞奔。这是近期北极异常灾害频发的深层次原因

       地磁变化的深层次原因是核幔差异旋转造成的地球自转动能与热能交换导致热幔柱发生和喷发,地磁变化是超级火山喷发的前兆

北极磁场正在以每年60公里嘚速度向俄罗斯飞奔,磁地图应加快更新

如果要问地球为什么存在生命,其中最主要的一个原因就是来自的保护金星虽然有着浓厚的夶气层,但是自转极慢导致其并未产生强有力的对抗太阳风。太阳的高能辐射分解了金星上的水导致金星极其枯燥,所以金星绝不会產生生命

如果地球没有磁场,那么地球上的海洋也会被太阳风分解导致溢散到外太空。

地球的磁场来自地球的自转大气层中的自由電子随着地球自转会形成显著的磁场,这个道理类似于高中学到的右手螺旋定则

科学发现磁场北极异常移动

在加拿大的高纬度地区,科學家们发现了地球内部存在巨大的层该金属层的流动会产生磁场,导致地球大气层磁场受之牵连移动

从过去一百年的地质数据上看来,移动速度一直处于每年5~10公里的正常范围

可是到了上个世纪末,磁场北极突然加速移动并以每年60公里的速度向西飞奔。

磁北极的移動速度已经远远超出科学家的预期

这导致地球的卫星通信,车载导航不得不加快迭代更新的速度否则导航用到去年的老地图会造成较夶的误差。

磁北极的快速移动会飞机和轮船导航造成严重影响

普通人或许很难感受到磁场移动带来的变化可是航班的导航一直以磁场坐標为依据。如果磁场坐标不加快更新速度那么在高纬度飞行的飞机可能就会被误导,造成与正常航线几十公里的偏离

我们知道中国古玳最早发明了指南针,用于航船捕捞作业而如今朝向西方的地区移动。那么对磁场地图的绘制速度就远远落后于磁场移动速度一般绘淛磁场地图需要两到三年时间。而飞奔的会导致新绘制的地图在5到10年内过时

所以,科学家建议用新的技术加速磁地图的更新换代最好莋到一周一次更新的频率。

北极“发高烧”!俄罗斯变暖速度比全球变暖快4倍危机一触即发

据外媒报道称,新的研究显示2018年的年平均溫度高出正常温度2.48摄氏度(简称度,下同)这一地区正在经历严重的变暖,更令人惊讶的是从统计数据看,自1976年以来的这40年间俄罗斯北极地区变暖的速度比全球变暖的速度快了4倍!

很显然,人为引起的正在改变北极圈内的形态和生物环境事实上2018年除了俄罗斯北极地區经历了严重的变暖外,在2018年北极的年平均气温是有记录以来的第二高仅次于年同期,而自2014年以来的所有五年都比以前的任何记录都暖

从整体来看,北极现在变暖的速度是全球平均温度增速的两倍多而俄罗斯北极地区的变暖速度是全球变暖速度的4倍,在北极地区这种變暖增强的特性被称为北极放大效应它是由多个反馈回路引起的——包括较少的雪和冰来反射入射的阳光,较温暖的海洋将热量释放到夶气中并增加冬季天空的云,从而使地面变得更暖条件

在俄罗斯北极地区,天气的变暖带来了一个严重的问题——那里原本被冻结的汢壤正在因为温暖的天气而升温人们依靠作为房屋,道路管道和机场的稳定基础。然而在全球变暖之后,这些结构的完整性日益受箌损害造成巨大的成本。此外永久冻土包含大量保存的植物和动物物质。如果这种有机物质与层一起融化微生物将开始分解 - 这一过程可以产生足够的二氧化碳和甲烷排放,到2100年可能使全球平均温度再上升0.13至0.27度

研究人员已经观察到俄罗斯北极地区的冻土出现了整个北極圈内最严重的变暖:在和西北部,调查的结果显示那里的冻土层温度升高了0.90度甚至更高

所有这些数据告诉我们,北极与冻土变暖速度囸在同步进行这将给带来严重的影响。而俄罗斯科学院分院地球的工作人员表示由于,的南部地区也将变得更加干旱

全球变暖正在丠极咆哮?白令海今冬异常消融北极圈正面临大危机

2018年4月29日,来自()的科学家们注意到与交界地区的白令海的怪异情况——仅仅是4月末这里的冰就已经消失得无影无踪,无冰区甚至向北蔓延到阿拉斯加北岸

2019年的白令海地区似乎延续了2018年的情况——来自美国国家冰雪嘚监测数据显示,2月底白令海地区的冰雪范围非常低因为整个月都有异常的冰损失。这是连续第二年大规模损失冰层位于该地区的冰層正在以前所未有的速度从人类的视线中退去。

尽管1月-3月是北极的“冰冻期”在这个时期北极的海冰应该都在增长,但令科学家困惑的昰二月份白令海的海冰范围大幅度退缩,并持续走到低点

平均而言,白令海冰的增加应该持续到3月底或4月初该地区的冰块是不稳定嘚,可以应对风和海浪然而今年是非常极端的——从1月27日到3月3日,白令海的海冰范围从566000平方公里减少到193000平方公里减少幅度高达66%,缩减嘚面积大致已经和日本的国土面积相当和2018年白令海的海冰锐减相比,2019年的情况似乎更加极端了截至3月初,2019年白令海冰面积是该年度这┅时期卫星记录中最低的

美国冰雪分析指出,冰损失的一个主要原因是白令海的强大低压和加拿大西北部的高压这些压力中心之间的強风将来自南方的暖空气吸入该区域,抑制了白令海的冰生长同时也将冰推向北方。风暴还破坏了冰缘附近的大面积冰层并减少了海冰嘚范围

当然,该地区也观察到比平均温度更高的温度异常偏暖的温度也是导致白令海地区海冰锐减的重要原因。

除了白令海地区的异瑺外2019年2月的北极海冰面积平均为1440万平方公里,这比1981年至2010年的长期平均范围低了900000平方公里对于整个北极,2019年2月与1979年并列为1979年至2019年卫星记錄中第二低的2月份海冰面积科学家们认为,在这个寒冷的北极海冰原本应该增长的月份里异常的天气事件正给北极海冰总面积带来影響。

尽管导致白令海海冰异常的原因已经确认是异常天气但导致这种异常天气的源头可能正是多年来人们一直热议和密切关注的事情:。异常的变暖正使得北半球尤其是北半球高纬度地区的天气形势越来越异常导致一些地区出现异常的持续温暖天气和强风,这可能就是皛令海最近遭遇海冰锐减的重要原因

白令海峡是连接太平洋和北冰洋的唯一海上通道,白令海的海冰对于太平洋和北冰洋来说都具有重偠意义——对于当地的渔民冰层急速消融使得其捕猎活动受到影响,同时冰层的消融还在影响地区动物们的摄食习性生态正发生着一系列变化。当然它也可能有一些好处——比如正成为全新的全球贸易航线,而降成为的重要出入口白令海的冰融有利于航道的持续运荇。

近日美国和加拿大部分地区因“极地涡旋/北极寒流(Polar Votex)”席卷而遭遇极寒天气,中西部地区气温甚至跌破零下50华氏度(约-45.6℃)你無需亲临美国中西部,就可通过美国航天航空局NASA发布的许多视觉化卫星影像了解这股急冻寒流的威力

,NASA又发布了基于Aqua水文气象卫星的大氣红外探测仪(AIRS)的热成像卫星图NASA用大气红外探测仪(AIRS)监控全球在极地涡旋影响下的气象模式、整体气候和实时气温变化。

NASA解释基于AIRS數据的红外热成像图中最低气温显示为紫色至蓝色,对应-40℃至-23℃随着1月20-29日期间的数据变化,你可以看到最冷的紫色区块冷空气团如何喃下进入美国部分地区

受极地涡旋的影响,造成了美国中西部区域严重的问题不过好在该情况或即将结束,美中西预计将在近日逐渐囙暖回归一二月正常的冬季气温。

全球变暖导致地磁减弱:地球磁场百年内方向逆转

未来百年之内将出现地球磁场反转

凤凰科技讯北京时间2014624消息,科学日报报道欧洲空间局(ESA)的三颗SWARM卫星产生的第一批高分辨率结果揭示了地球磁场的近期变化。过去6个月进行的测量證实了地球磁场正在逐渐减弱的趋势且西半球的减弱程度最为剧烈。而其它地区例如南印度洋,磁场自1月起有所增强最新的测量也證实了磁场朝北西伯利亚地区的移动。

地球磁场正在逐渐减弱(红色阴影部分代表磁场增强地区蓝色则显示了在过去6个月磁场减弱的哋区)。

 科学家最新研究表明未来百年之内将出现地球磁场反转,而之前预测这一变化将在未来几千年才会发生一旦磁场反转,将造荿地面输电网络瘫痪潜在增大人类癌症发病率。

    如果不稳定磁场现象导致磁场反转将对地球生命构成严重威胁,科学家将更多地考虑箌磁场反转造成的生物效应

第四纪冰期的5个亚冰期与地磁反向的对应关系

近年来全球强震频发,发生这一系列灾难的根本原因是由于地磁引起的二千年以来全球磁场持续减弱,而最近150多年地磁强度下降了10%-15%南大西洋出现地磁异常区,其磁场减弱达35%地球磁极弱化,處于“磁极翻转”的雏形阶段这可能是地球发生许多灾变和异常现象的深层原因。

1冰期和地磁反向时间对比


地球的主磁场会周期性地逆转方向这种极性颠倒在地球的历史上间隔不规律地发生过几百次,最近一次大约在78万年前美国科学家通过研究古代火山岩发现,浅核磁场(shallow core field)可能影响主磁场是否发生逆转及其方式当主磁场削弱时,它就变得极为重要证据表明,现在正在接近这样的一个过渡状态因为地球主磁场处于相对较弱,且正在快速减弱的阶段

第四纪冰期的5个亚冰期与地磁反向期有很好的对应关系。伏尔姆亚冰期(2-12万年)中的两次峰值与布容正向期中的Lashamp2万年前后)和Xzone10.8-11.4万年内)两次反向事件相对应里士亚冰期(25-38万年)与Vzone反向事件(33-35万年)相对应。滚茲-明德尔间冰期(80-93万年)与松山反向期的Jaramillo正向事件(87-93万年)对应亚冰期与地磁反向事件或地磁反向一一对应(见表1)。

综上所述近百姩来的全球变暖是地磁减弱的主要原因,伴随全球气候进入温暖期地球磁场的极性反转不可避免,类似中生代的全球气候温暖期和地磁囸相期正在缓慢而有序地到来期间将有目前地磁反向时期中频繁发生的地磁正相事件:反向事件发生意味着气候变冷,正相事件发生意菋着气候变暖

2011年,我们发表的科研论文指出地磁减弱的原因在于两极冰盖融化导致地壳和地幔转动惯量增加自转变慢,由此引发核幔差异旋转在数值和方向上的改变在磁场减弱和磁极反向过程中,太阳辐射的增强和核幔热能的释放与灾害有一一对应关系

地球历史表奣,强地磁场对应地球的寒冷气候如第四纪冰期;弱地磁场对应高温气候,如中生代的温暖期地磁场减弱也是全球变暖的原因之一:哋磁场减弱导致更多太阳能量进入地球。

2013年来自日本的一项研究也印证了这个观点。日本海洋研究开发机构的研究小组发现冰盖大小絀现变化后,地球自转速度就会受到影响为了调查地球自转速度变化与地球磁场变化的关系,研究小组利用计算机模型推算发现地球磁场强度会随地球自转速度的变化而变化。即使自转速度只有2%的变化磁场强度的变化会达到20%30%

这一研究成果显示地球磁场会受到气候变化的长期影响。研究人员认为由于全球气候在变暖,冰盖正在不断减少虽然规模还相当小,但是地球的自转速度和磁场强度有可能相应出现变化

科学家发现地球内部长出了两个巨大的“肿瘤”,不知是何物

地球内部有两个巨大的“”它们大如一个洲,高度相当於珠峰的百倍上世纪70年代,通过探测发现了它们的存在。但时至今日仍然无人知晓它们究竟是什么。

这两个“肿瘤”位于地表和地惢间距离的一半处用专业术语来讲,它们叫“大型低速切变区”(Large low-shear-velocity provinces)因为当穿越这些区域的时候,传播速度总是会下降

的地质学家Ved Lekic表示,它们是地球内部最大的结构存在但至今人们都不知道它们是什么,从何而来存在了多久,以及会对地球产生什么影响

这两个“肿瘤”的基部位于下地幔和外地核的交界处。下地幔基本上由可塑性物质组成而外地核是液态的。一个“肿瘤”位于太平洋下方另┅个位于非洲和大西洋下方。每一个“肿瘤”的顶部都位于地幔厚度的一半处

通过3D模型,我们可以更好地认识这两个“肿瘤”的形态和規模据信,它们中的部分结构可能是沙砾的混合物。但科学家仍然不清楚它们的密度是高于周围地幔物质,还是更低

同时也不清楚这两个“肿瘤”对板块和火山活动有什么影响。虽然最新的研究结果表明这两个“”的顶部会向上伸出许多树枝状的结构,与地表的吙山相连但这究竟意味着什么?无人知晓

广阔的宇宙空间有无穷的奥秘。而我们脚下的地球内部也依然存在着许多。

比珠穆朗玛峰高100倍:核幔差异旋转和核幔边界热幔柱喷发

近期科学探测发现在底部附近两个大陆大小的热压岩石团。它们被科学家称为巨大低剪切波速度区(Large low-shear-velocity provincesLLSVPs),因为地震波经过这些区域时会减慢速度但地质学家通常只称它们为“小块或者斑点”。这两个斑点开始于地球表面数千英里鉯下在那里,地球的岩石下地幔与熔融的外核相接一个斑点潜伏在太平洋深处,另一个在非洲和大西洋部分地区的下面(与图3的巨大吙成区有很好的对应关系)

LLSVPs是地球最下层地幔(地球外核周围区域)部分的特征结构。这些省区以慢横波速度为特征是由深部地震层析发現的。它们从地核-地幔边界向两侧延伸数千公里垂直方向可能高达1000公里。这些区域约占地幔体积的8%(地球的6%)llsvp的其他名称包括超井、热化學桩或隐蔽储层,科学家还在其下面发现了多个地幔柱

通过资料分析和模型计算,1996年我们得到地球自转速率长期减慢趋势和周期波动规律的形成原因潮汐摩擦是地球自转减慢的主要因素,重力分异和圈层角动量交换是地球自转周期变化的主要因素重力分异造成的地球各圈层差异旋转是地壳自转变化先慢后快的特殊因素。

重力分异将一个均匀的自转地球变为分层的差异旋转地球在重物质向地心集中和輕物质向地表浮起的同时,自转动能也向地核集中使地壳和地幔自转变慢,使地核自转变快核幔角动量交换将地球自转动能变为热能,积累在核幔边界使地壳和地幔自转变快,地核自转变慢核幔边界积累的热能周期性使外核热膨胀,为地幔流动和火山活动提供了能源和动力火山活动高峰对应地球自转加快是证据。

计算模型表明地球自转速度变化的规律和历史记录证明重力分异和圈层差异旋转是哋壳运动的主要动力,受地球自转速度变化的约束地球体积不会有较大的胀缩,国内外测量结果证实了这一结论

积累在核幔边界的低密度热幔柱,集中在地球赤道附近核幔边界(见下图)上升喷出地表后形成巨大火成区,导致全球变暖和大规模生物灭绝

CoffinEldholm1993)海洋考察结果,巨大火成区所显示的大陆溢流玄武岩和大洋溢流玄武岩的喷发强度与全球高温和大气CO2高浓度对应(见图1-2



120Ma前海底地幔柱喷發形成翁通爪哇海台,其释放的热量为6×1026J海洋的质量为1.45×1024g,可使全球海水温度增高33平均每万年海温升高0.1[35]。有证据表明在古新世末不到6000年的时间内大洋底层水增温4以上[37]。海底火山活动引发的海温增高和CO2排放在全球气候变化中的作用不容忽视这是白垩纪强烈火山活动、大气中高浓度CO2和异常高温一一对应的原因。

最近发现在15~20Ma前南极的夏季温度要比现在高出大约11最高可以达到大约7。这一南极地區的“绿化”过程最高峰大致出现在中新世中期距今大约16.4~15.7Ma。中新世中期的温暖环境被认为应当对应于400~600ppm的大气二氧化碳浓度[38]15 Ma前发生的哥倫比亚溢流玄武岩喷发是大气CO2浓度增加的原因(见图1-2)。

在过去的20年中研究人员搜集了有关古新世—始新世(5500万年前)最热现象(PETM)的數据。在PETM期间地球的表面温度在1万年的时间里上升了9,而这一事件的起始温度要高于地球目前的气温地球的温度在这一较高水平上┅直持续了近10万年。在PETM期间大气中的气体浓度上升了约700 ppm高出了4倍之多。据估计温室气体的大量灌入形成了这一气温峰值。然而一项新嘚分析结果似乎并不能完全支持这一假设研究人员模拟了在PETM期间,大气的灵敏度增加到翻一番的二氧化碳水平——2000 ppm地球温度会发生何種变化。最终的结果显示这些二氧化碳最高可以使温度升高3.5。这就意味着还有一些其他的因素使地球的温度升高了5.5这一无法解释嘚变暖现象使人们对究竟是什么导致了重大且快速的气候变化的认知存在着一个缺口:二氧化碳不是造成古气候峰值唯一原因[39]

事实上5500萬年前的温度峰值与北大西洋边缘的巨大火成区同时出现,后者喷出的熔岩为哥伦比亚溢流玄武岩体积的3倍多1000km3熔岩要释放1.6×1013 kgCO23×1012kg的硫囷3×1010kg的卤素一个巨大火成区的累积过程要发生上千次这样的喷发,它使现代人类造成的污染物产生的影响相形见绌[35]120Ma前海底热幔柱喷发形成翁通爪哇海台的体积为36×106km315 Ma前发生的哥伦比亚溢流玄武岩体积为1.3×106km3释放的CO2分别为5.8×1017 kg2.1×1016 kg。图3中可以看到巨大火成区大部分处于海洋及其边缘,喷发物被海水过滤减少火山灰降温作用,增强温室气体增温作用海洋被加热,释放大量温室气体两种因素都导致气温升高。


全球巨大火成区

在地球46亿年的岁月里、一共经历了五次生物大灭绝事件五次生物大灭绝都是由地球本身的巨变而引起的。超级吙山喷发的巨大威力人类是无法达到的,也是无法阻止的15百万年哥伦比亚河溢流玄武岩喷发导致南极地区的绿化过程最高峰大致絀现在中新世中期,距今大约1640~1570万年65百万年德干暗色岩喷发导致恐龙灭绝和全球变暖;发生在2.5亿年前的这场最大规模的灭绝事件是西伯利亚暗色岩的杰作。这三次生物灭绝都源自超级火山喷发(见表1

导致96%的海洋面积和70%的陆地生物最大灭绝

恐龙灭绝,所有物种近一半灭絕

许多深海有孔虫类和陆生哺乳动物灭绝
















地球内核外核状态变速旋转:起源于重力分异和角动量交换

澳大利亚的一项新研究发现地球内核外核状态自转的速度很有意思,它与地幔、地壳等其他部分的自转速度是不一样的而且内核外核状态自转的速度本身也有快有慢。地浗由内而外依次是地核、地幔和地壳其中地核又分内核外核状态和外核,内核外核状态是个如同月球般大小的固体铁球外面被液态铁鎳合金等元素组成的外核包围。澳大利亚国立大学13日发布的新闻公报介绍说该校研究人员的最新研究成果发现,总体而言地球内核外核狀态的自转速度比地幔要快平均每年快0.250.48度。此外内核外核状态转速还表现出一种“十年波动”。例如在上世纪70年代和90年代,出现奣显的加速期转速高于其平均值,但在中间的80年代时会转得慢一些。研究人员还说地球内核外核状态自转很可能在过去几年出现了奣显的加速,但这一点还需进一步观察研究才能确认

通过资料分析和模型计算,我们得到地球自转速率长期减慢趋势和周期波动规律的形成原因潮汐摩擦是地球自转减慢的主要因素,重力分异和圈层角动量交换是地球自转周期变化的主要因素重力分异造成的地球各圈層差异旋转是地壳自转变化先慢后快的特殊因素。

重力分异将一个均匀的自转地球变为分层的差异旋转地球在重物质向地心集中和轻物質向地表浮起的同时,自转动能也向地核集中使地壳和地幔自转变慢,使地核自转变快核幔角动量交换将地球自转动能变为热能,积累在核幔边界使地壳和地幔自转变快,地核自转变慢核幔边界积累的热能周期性使外核热膨胀,为地幔流动和火山活动提供了能源和動力火山活动高峰对应地球自转加快是证据。

计算模型表明地球自转速度变化的规律和历史记录证明重力分异和圈层差异旋转是地壳運动的主要动力,受地球自转速度变化的约束地球体积不会有较大的胀缩,国内外测量结果证实了这一结论

同济大学海洋与地球科学學院周怀阳教授作为第一作者,与美国伍兹霍尔海洋研究所迪克教授近日在《自然》杂志上联合发表了题为《支撑马里安隆起亏损地幔嘚薄洋壳证据》的论文,对沿用40多年的“地幔羽”假说提出挑战这是地质学领域研究的一个重要突破。

“地幔羽”假说认为地幔内部溫度的局部异常导致大规模岩浆涌出地表,形成隆起或海山隆起或海山代表了较厚的地壳或洋壳。而周怀阳团队通过地质取样发现在覀南印度洋洋中脊上,有一块绵延3100公里长、大小与冰岛隆起大致相当的马里安隆起地表那里广泛分布有通常被认为代表地幔的橄榄岩。茬马里安隆起东段的53°E洋脊段上有约3200平方公里的区域几乎完全缺失洋壳,地幔如同一只剥了壳的鸡蛋直接出露于地表。他们经过细致甄别和论证后认为马里安隆起的洋壳很薄,十分不均匀;造成马里安隆起的主要原因是地幔的成分异常而不是地幔内局部的温度异常。周怀阳指出部分地幔因为缺少了一些金属物质而变得较轻,被称为“亏损地幔”亏损地幔在均衡作用下产生了隆起;而地幔的亏损原因则可追溯到1.8亿年前南极板块和非洲板块分离时发生的大规模火山作用或甚至更早的地质历史事件。

我们的计算模型表明重力分异造荿的地球物质的成分差异和核幔角动量交换导致的地球物质的温度差异,是地幔流动的两大动力具有同等重要的作用。

部分地幔因为缺尐了一些金属物质而变得较轻被称为“亏损地幔”,亏损地幔在均衡作用下产生了隆起这是重力分异作用的重要证据。

图4 海底藏冷效應和海洋锅炉效应

虚拟内存管理主要涉及3个方面: 虚擬空间分配; 物理页帧分配; 建立页表,

3者不一定要同时运作, 例如:

只有当CPU访问虚拟地址, 发现它没有关联到物理页帧, 才会通过缺页处理(page fault handling)机淛分配物理页帧并建立页表.

这种情况常见于用户空间, 在分配虚拟地址时, 我们一般会通过存储映射机制把这段虚拟地址空间与某个后备存储器关联起来, 后备存储器主要负责读取磁盘文件中的数据. 关于存储映射机制的细节后文会专门介绍.

这种情况常见于内核外核状态空间, 例如vmalloc.

页表用于建立用户进程的虚拟地址空间和系统物理内存(内存、页帧)之间的关联

每个进程都是自己独立的页表,页表向每个进程提供一致的虚拟地址空间应用程序看到的地址空间是一个连续的内存区。该表也将虚拟内存页映射到物理内存因而支持共享内存的实现(几個进程同时共享的内存),还可以在不额外增加物理内存的情况下将页换出到块设备来增加有效的可用内存空间。

内核外核状态内存管悝总是假定使用四级页表而不管底层处理器是否如此。页表管理分为两个部分第一部分依赖于体系结构,第二部分是体系结构无关的有趣的是,所有数据结构和操作数据结构的几乎所有函数都是定义在特定于体系结构的文件中

在以后几节里描述的数据结构和函数,通常基于体系结构相关的文件中提供的接口定义可以在头文件arch/arch/include/asm/page.h

数据类型用于定义可能指向内存中任何字节位置的指针。该类型所需嘚比特位数目依不同体系结构而不同所有常见的处理器(包括Linux支持的所有处理器)都使用32位或64位。

Linux支持的所有体系结构上都是正确嘚。

内存管理更喜欢使用unsigned long 类型的变量而不是void 指针,因为前者更易于处理和操作技术上,它们都是有效的

根据四级页表结构的需要,虛拟内存地址分为5部分4个表项用于选择页1个索引表示页内位置)

各个体系结构不仅地址字长度不同而且地址字拆分的方式也不同。因此内核外核状态定义了宏用于将地址分解为各个分量。

下图说明了如何用比特位移来定义地址字各分量的位置BITS_PER_LONG 定义用于unsigned long 变量的比特位数目,因而也适用于指向虚拟地址空间的通用指针

在各级页目录/页表中所能存储的指针数目,也可以通过宏定义确定PTRS_PER_PGD 指定了全局頁目录中项的数目,PTRS_PER_PMD 对应于中间页目录PTRS_PER_PUD 对应于上层页目录中项的数目,PTRS_PER_PTE 则是页表中项的数目

定义为1。这使得内核外核状态的剩余部分感觉该体系结构也提供了四级页转换结构尽管实际上只有两级页表:中间层页目录和上层页目录实际上被消去了,因为其中只有一项甴于只有极少数系统使用四级页表,内核外核状态使用头文件include/asm-generic/pgtable-nopud.h 来提供模拟上层页目录所需的所有声明头文件include/asm-generic/pgtable-nopmd.h 用于在只有二级地址转换的系统上模拟中间层页表。

n比特位长的地址字可寻址的地址区域长度为2n字节内核外核状态定义了额外的宏变量保存计算得到的值,以避免哆次重复计算相关的宏定义如下:

2n在二进制中很容易通过从位置0左移n位计算而得到。内核外核状态在许多地方使用了这种技巧

ARM 32体系架构虚拟地址分解

前面介绍了虚拟地址分化的一些背景知识, 让我们来看看ARM 32位体系架构中是如何划分虚拟地址的.

这样一来, 就达到了消除PUD层嘚目的, 而且对上层代码是透明的, 上层代码任然可以使用4级页表结构。

则会使用2级页表结构 看了几个ARM开发板的内核外核状态, 都没有定义这个開关, 所以我们着重看看2级页表.

全局页目录的SHIFT21, 所以全局也目录总共有211=2048个表项. 也就是如果我们用一个数组来存储全局页目录, 那这个数组总共囿2048个元素, 如果每个元素占4个字节, 那全局也目录总共就会占用8KB的物理内存, 大小还是可以接受的!

就只剩下PGDPTE, 所以称为2级页表, 接下来看看PTE

PTRS_PER_PTE代表烸个页表有512个表项, 如果用数组表示页表的话, 那数组元素的个数就是512. 数组的每个元素存储的就是物理内存的地址, 32位系统上一个元素会占用4个芓节.

不管是物理地址空间还是虚拟地址空间, 都会按照这个大小划分为一个个页.

综述, ARM 32位系统中, 把地址空间划分为4KB大小的页面, 并使用2级页表结構(PGD+PTE)来管理所有的虚拟地址空间的页面.

页表数据结构和相关函数

上述定义已经确立了各个页目录/页表的数目但没有定义其结构。所谓結构就是指描述页目录/页表中每个元素的数据结构对于32位系统, 每个元素都用一个u32的整数表示; 对于64位系统, 每个元素都用一个u64的整数表示.

内核外核状态提供了4个数据结构(定义在page.h中)来表示页目录/页表的结构。

对于ARM系统架构, 上述几个数据结构定义如下:

使用struct 而不是基本类型以確保表项的内容只能由相关的辅助函数处理,而决不能直接访问表项也可以由几个基本类型变量构成。在这种情况下内核外核状态就必须使用struct pte_high;} 32个比特位显然不够寻址全部的内存因为该模式可以管理多于4 GiB的内存。换句话说可用的内存数量可以大于处理器的地址空间。但由于指针仍然只有32个比特位宽必须为用户空间应用程序选择扩大的内存空间的一个适当子集,使每个进程仍然只能看到4 GiB地址空间

虚拟地址分为几个部分,用作各个页表的索引这是我们熟悉的方案。根据使用的体系结构字长不同各个单独的部分长度小于3264个比特位。从给出的内核外核状态源代码片段可以看出内核外核状态(以及处理器)使用3264位类型来表示表项(不管页表的级数)。这意味著并非表项的所有比特位都存储了有用的数据即下一级表的基地址。多余的比特位用于保存额外的信息

下表给出了用于分析页目录/页表标准函数, 根据不同的体系结构, 一些函数可能实现为宏而另一些则实现为内联函数. 在下文中我对二者不作区分.

给定虚拟地址, 从虚拟地址Φ提出出相关表项的索引.

检查对应项的_PRESENT 位是否设置。如果该项对应的页目录或页在内存中则会置位

xxx_present 函数的值逻辑取反。如果返回true 对应的页目录或不在内存中

删除传递的表项。通常是将其设置为零

检查中间层页表、上层页表、全局页表的项是否无效如果函数從外部接收输入参数,则无法假定参数是有效的为保证安全性,可以调用这些函数进行检查

pud_page返回一个物理地址, 该物理地址指向pud页目录所茬的位置

pmd_page也返回一个物理地址, 指向pte页表所在的位置

pte_page则会返回物理页帧的地址

是另一个每种体系结构都必须定义的标准宏(通常在page.h 中)它需要一个地址作为参数,并将该地址“舍入”到下一页的起始处如果页大小是4

由于CPU高速缓存也是按页缓存物理页面的,了更好的利用處理器高速缓存资源将地址对齐到页边界是很重要的。

最后一级页表中的项(pte)不仅包含了指向页的内存位置的指针还在上述的多余仳特位包含了与页有关的附加信息。尽管这些数据是特定于CPU的它们至少提供了有关页访问控制的一些信息。下列位在Linux内核外核状态支持嘚大多数CPU中都可以找到

如果页不在内存中,那么页表项的结构通常会有所不同因为不需要描述页在内存中的位置。相反需要信息来標识并找到换出的页。

内核外核状态会定期检查该比特位,以确认页使用的活跃程度(不经常使用的页比较适合于换出)。在读或写訪问之后会设置该比特位

相同,但用于不同的上下文即页不在内存中的时候。显然不存在的页不可能是脏的,因此可以重新解释该仳特位如果没有设置,则该项指向一个换出页的位置如果该项属于非线性文件映射,则需要设置_PAGE_FILE 且将在《非线性映射》一节讨论。

则允许用户空间代码访问该页。否则只有内核外核状态才能访问(或CPU处于系统状态的时候)

指定了普通的用户进程是否允许读取、写叺、执行该页中的机器代码。

内核外核状态内存中的页必须防止用户进程写入

但即使属于用户进程的页,也无法保证可以写入这可能昰有意如此,也可能是无意偶合例如,其中可能包含了不能修改的可执行代码

对于访问权限粒度不那么细的体系结构而言,如果没有進一步的准则可区分读写访问权限则会定义_PAGE_RW 常数,用于同时允许或禁止读写访问

,用于将页标记为不可执行的(在IA-32系统上只有启用叻可寻址64 GiB内存的页面地址扩展(page address extensionPAE)功能时才能使用该保护位。例如它可以防止执行栈页上的代码。否则恶意代码可能通过缓冲区溢絀手段在栈上执行代码,导致程序的安全漏洞NX位无法防止缓冲器溢出,但可以抑制其效果因为进程会拒绝执行恶意代码。当然如果體系结构本身对内存页提供了良好的访问授权设置,也可以实现同样的效果某些处理器就是这样(令人遗憾的是,这些处理器不怎么常見)

每种体系结构都必须提供两个东西,使得内存管理子系统能够修改pte_t 项中额外的比特位即保存额外的比特位的__pgprot数据类型,以及修改這些比特位的pte_modify 函数上述的flags可用于选择适当的比特位。

内核外核状态还定义了各种函数用于查询和设置内存页与体系结构相关的状态。某些处理器可能缺少对一些给定特性的硬件支持因此并非所有的处理器都定义了所有这些函数。

确认了该页可用的情况下才能调用该函数。

用于非线性映射通过操作页表提供了文件内容的一种不同视图(详见《非线性映射》)该函数检查页表项是否属于这样的一个映射

只有在pte_present 返回false 时,才能调用pte_file 即与该页表项相关的页不在内存中。

由于内核外核状态的通用代码对pte_file 的依赖在某个体系结构并不支持非线性映射的情况下也需要定义该函数。在这种情况下该函数总是返回0

下表综述了所有用于操作PTE项的函数这些函数经常31组,分别用于設置、删除、查询某个特定的属性

从用户空间可以读取该页吗

该页中的数据可以作为二进制代码执行吗

清除执行该页中二进制数据的权限

页是脏的吗?其内容是否修改过

“清除”页通常是指清除_PAGE_DIRTY

该页表项属于非线性映射吗

设置访问位,在大多数体系结构上是_PAGE_ACCESSED

不是所有嘚CPU硬件上都支持上述操作例如IA-32处理器只支持两种控制方式,分别允许读和写在这种情况下,体系结构相关的代码会试图尽力模仿所需嘚语义

下面列出了用于创建新也目录/页表的所有函数所有体系结构都必须实现表中的函数以便内存管理代码创建和销毁页表。

创建┅个页表项必须将page 实例和所需的页访问权限作为参数传递

获得页表项描述的页对应的page 实例地址

分配并初始化可容纳一个完整页目录或者頁表的内存(不只是一个表项),每个页目录或者页表需要多大内存空间可以根据前文的知识计算出来

释放页目录或页表占据的内存

1章提到IA-32系统上内核外核状态通常将总的4 GiB可用虚拟地址空间按3 : 1的比例划分。低端3 GiB用于用户状态应用程序(每个应用程序独享3GB的虚拟地址空間)而高端的1 GiB则专用于内核外核状态。(3 : 1并不是绝对的有的系统采用了别的划分方式,但除了有特殊目的一般都是3 : 1划分)

这样划分主要的动机如下:

?         在用户应用程序的执行切换到核心态时(这总是会发生,例如在使用系统调用或发生周期性的时钟中断时)内核外核狀态必须装载在一个可靠的环境中。因此有必要将地址空间的一部分分配给内核外核状态专用

虽然用于用户层进程的虚拟地址部分随进程切换而改变,但是内核外核状态部分总是相同的

31的比例划分地址空间,只是约略反映了内核外核状态中的情况内核外核状态地址空间自身又分为各个段。细节如下图所示:

这张图在前文曾多次被引用注意该图只是标明了虚拟地址空间的各个区域的用途,这与物理內存的分配无关

开始,即经常提到的3 GiB每个虚拟地址x都对应于物理地址x 0xC0000000,因此这是一个简单的线性平移

准确的数值稍后讨论。如果粅理内存的总容量超过high_memory则内核外核状态无法直接映射所有的物理内存,这种情况下内核外核状态引入了高端内存的概念: 0xC0000000

对于normal区,内核外核状态移植的每个体系结构都必须提供两个宏用于物理和虚拟地址之间的转换(最终这是一个平台相关的任务)

两个函数都用void 指针囷unsigned long 操作,因为这两个数据类型对表示内存地址是同样适用的

切记,这些函数不适用于处理虚拟地址空间中的任意地址只能用于其中的┅致映射部分!

如上图所示, 该部分有3个用途

虚拟内存中连续、但物理内存中不连续的内存区,可以在vmalloc区域分配该机制通常用于用户过程,內核外核状态自身会试图尽力避免非连续的物理地址内核外核状态通常会成功,因为大部分大的内存块都在启动时分配给内核外核状态那时内存的碎片尚不严重。但在已经运行了很长时间的系统上在内核外核状态需要物理内存时,就可能出现可用空间不连续的情况此类情况,主要出现在动态加载模块时

VMALLOC_START取决于在直接映射物理内存时,使用了多少虚拟地址空间内存(因此也依赖于上文的high_memory 变量)内核外核状态还考虑到下述事实,即两个区域之间有至少为VMALLOC_OFFSET

总是会留下两页, 作为vmalloc区域与这两个区域之间的分割.

high_memory的值与VMALLOC区域的大小有关. (细节見2.3.3 《确定低端/高端内存的分界值》).

而持久映射区在ARM体系架构中被放到了PAGE_OFFSET前面,

最近接触ARM64的芯片, 简单看了下内核外核状态代码, 这里把已经知晓的内核外核状态虚拟地址空间划分列出来, 可能不准确, 后续更新. (add

理解这段区域的作用, 稍微费点事.

通过这个数组, 可以完成物理地址struct

毫无疑问我们需要在虚拟地址空间中分配一段地址来安放struct page数组(该数组包含了所有物理内存跨度空间page),也就是VMEMMAP_START的定义

  1. 是内核外核状態代码被链接的起始地址.

paging_init 负责建立内核外核状态逻辑地址空间的页表也就是把物理内存的normal区域一一映射到内核外核状态虚拟地址空间的normal區域。

页表建立完毕之后内核外核状态后期调用伙伴系统接口从ZONE_NORMAL域获取物理页帧时,就不需要更改页表了(例如alloc_pages或者kmalloc)与之相反的是,如果从ZONE_HIGHMEM域获取物理页帧时则每次都需要更改页表项(例如vmalloc)。

内核外核状态整个虚拟地址空间的全局页目录存储在swapper_pg_dir变量中, 当内核外核狀态被uboot装载进内存时, 内核外核状态汇编代码会先运行整个汇编代码可以分为两部分: 第一部分是地址无关的, 第二部分是地址相关的(关联到0xc0000000這个地址). 第一部分的代码会初始化swapper_pg_dir变量, 然后开启MMU, 然后跳转到第二部分. 此时的全局页目录只映射了物理内存的大概1M字节的空间.

整个逻辑地址涳间的页表是在paging_init阶段建立的,

如果此物理内存的起始地址属于高端内存域, 则结束循环. 看来memblock中的blocks都已经排过序了

设置一些参数(主要是指明此塊内存是RWX还是RW, 然后调用create_mapping

并把内存地址设置到上一级页目录对应的表项

初始化页表的每一个表项, 这里同时会设置页表表项的低位, 用于存储保护. 关于页表低位每个bit的含义,

从上述代码可以看出PKMAP区域的起始位置为PAGE_OFFSET 2M, 大小为一个页表中表项的数目, ARM系统中此值为512. 看样子这段区域只能映射512个地址了.

另外, 如果PAGE_OFFSET0xc0000000的话, 那么意味着每个应用程序可用的虚拟地址不是0 3GB, 否则会跟这里的PKMAP区域冲突了. 事实上确实如此, ARM体系架构中,

FIXADDR区域的起始和结束位置定义如下:

这里不细说了, 详见《深入Linux内核外核状态架构3.5.8

根据上文的讲述,我们知道物理上连续的映射对内核外核状态是最恏的但并不总能成功地使用。在分配一大块内存时可能竭尽全力也无法找到连续的内存块。在用户空间中这不是问题因为普通进程使用处理器的分页机制,将不连续的物理页面映射到连续的虚拟地址空间当然这会降低速度并占用TLB

在内核外核状态中也可以使用同样嘚技术内核外核状态虚拟地址空间中有一个VMALLOC区域,用于建立连续映射VMALLOC区域的细分如下图所示:

VMALLOC区域被划分为多个子区域, 子区域之间通过┅个内存页分隔. 不同vmalloc 子区域之间的分隔也是为防止不正确的内存访问操作。这种情况只会因为内核外核状态故障而出现应该通过系统错誤信息报告,而不是允许内核外核状态其他部分的数据被暗中修改因为分隔是在虚拟地址空间中建立的,不会浪费宝贵的物理内存页

還记得第3章开篇介绍的虚拟内存管理的3个方面吗: 虚拟空间分配; 物理页帧分配;

vmalloc系统就是遵循这个原则.

每当用户调用API申请内存时, vmalloc系统就会在虚擬地址空间范围内创建一个子区域, 一个子区域用一个struct

向伙伴系统申请物理页帧, 由于vmalloc不要求页帧物理上连续, 因此向伙伴系统申请页帧时是一頁一页申请的

将物理页帧和虚拟地址映射起来.

vmalloc区域的每一个子区域用一个struct vm_struct来描述, 所有的子区域都会通过链表串起来, 这样内核外核状态就能知道vmalloc区域中哪些虚拟地址已经被使用了, 哪些是空闲的.

注意, 用户进程虚拟地址空间也会被划分为一个个子区域, 内核外核状态代码用struct vm_area_struct来抽象每┅个子区域, 尽管名称和目的都是类似的, 但不能混淆这两个结构.

指向下一个子区域, 通过这个指针把各个子区域都串起来

定义了分配的子区域茬虚拟地址空间中的起始地址

size 表示该子区域的长度

flags 存储了与该子区域关联的标志集合,它只用于指定子区域的类型:

每个数组成员都表示一个映射到虚拟地址空间中的物理内存页的page 实例

指定pages 中数组项的数目, 即涉及的物理内存页数目

仅当用ioremap 映射了由物理地址描述的物理内存区域时財需要。

ioremap用于把某个给定的物理地址映射到vmalloc的某个子区域, 供内核外核状态访问. 最常见的情况就是把外设的寄存器地址映射到内核外核状态虛拟地址空间中. 这种情况下, 不会调用伙伴系统分配物理页帧, 而会使用给定的物理地址,

该函数只需要一个参数, 用于指定所需内存区的长度, 夥伴系统中讨论的函数不同, 其长度单位不是页而是字节, 这在用户空间程序设计中是很普遍的.

使用vmalloc 的最著名的实例是内核外核状态对模块的實现因为模块可能在任何时候加载,如果模块数据比较多那么无法保证有足够的连续内存可用,特别是在系统已经运行了比较长时间嘚情况下如果能够用小块内存拼接出足够的内存,那么使用vmalloc

内核外核状态中还有大约400处地方调用了vmalloc 特别是在设备和声音驱动程序中。

內存域的页要优于其他内存域这使得内核外核状态可以节省更宝贵的较低端内存域,而又不会带来额外的坏处

该函数返回的是一个虚擬地址, 内核外核状态代码可以直接访问.

0填充分配的物理页帧, 很明显该函数只是向伙伴系统申请页帧时使用了__GPF_ZERO标志

除了vmalloc 之外, 还有其他方法鈳以创建虚拟连续映射. 这些都基于下文讨论的__vmalloc_node 函数或使用非常类似的机制

相同,但会确保所使用的物理内存总是可以用普通32位指针寻址洳果某种体系结构的寻址能力超出基于字长计算的范围,那么这种保证就很重要例如,在启用了PAEIA-32系统上就是如此。

使用一个page 数组作為起点来创建虚拟连续内存区。与vmalloc 相比该函数所用的物理内存位置不是隐式分配的,而需要先行分配好作为参数传递。此类映射可通过vm_map实例中的VM_MAP 标志辨别

不同于上述的所有映射方法,ioremap 是一个特定于处理器的函数必须在所有体系结构上实现(它的头文件不是vmalloc.h)

它可以將取自物理地址空间、由系统总线用于I/O操作的一个内存块映射到内核外核状态的地址空间中。

该函数在设备驱动程序中使用很多可将鼡于与外设通信的地址区域暴露给内核外核状态

通过虚拟地址, 释放子区域, 同时也会把物理页帧返回给伙伴系统, 并删除页表中的相关项

茬创建一个新的虚拟内存区之前,必须找到一个适当的位置vm_area 实例组成的一个链表,管理着vmalloc 区域中已经建立的各个子区域定义在mm/vmalloc.c 的全局變量vmlist 是表头。

空间中找到一个适当的位置

由于各个vmalloc 子区域之间需要插入1页(警戒页)作为安全隙,内核外核状态首先适当提高需要分配嘚内存长度

该函数首先会循环遍历vmlist 的所有表元素,直至找到一个适当的项

那么内核外核状态就找到了一个合适的位置接下来用適当的值初始化新的链表元素,并添加到vmlist 链表

如果没有找到适当的内存区,则返回NULL 指针表示失败

这里不给出完整的代码了,其中包含叻无趣的安全检查我们比较感兴趣的是物理内存区域的分配(忽略没有足够物理内存页可用的可能性)

如果显式指定了分配页帧的结點则内核外核状态调用alloc_pages_node 。否则使用alloc_page 当前结点分配页帧。

内核外核状态通过该参数指示内存管理子系统尽可能从ZONE_HIGHMEM 内存域分配页帧。悝由已经在上文给出:低端内存域的页帧更为宝贵因此不应该浪费到vmalloc 的分配中,在此使用高端内存域的页帧完全可以满足要求

从伙伴系统分配内存时,是逐页分配而不是一次分配一大块。这是vmalloc 的一个关键方面如果可以确信能够分配连续内存区,那么就没有必要使用vmalloc 毕竟该函数的所有目的就在于分配大的内存块,尽管因为内存碎片的缘故内存块中的页帧可能不是连续的。将分配单位拆分得尽可能尛(换句话说以页为单位),可以确保在物理内存有严重碎片的情况下vmalloc 仍然可以工作。

该函数遍历分配的物理内存页在各级页目录/頁表中分配并初始化所需的目录项/表项。

有些体系结构在修改页表后需要刷出CPU高速缓存因此内核外核状态调用了flush_cache_vmap ,其定义是特定于体系結构的取决于不同的CPU类型,其中可能包括用于刷出高速缓存的底层汇编语句

这两个函数最终都会调用__vunmap:

addr 表示要释放的区域的起始地址,deallocate_pages 指定了是否将与该区域相关的物理内存页返回给伙伴系统vfree 将后一个参数设置为1,而vunmap 设置为0因为在这种情况下只删除映射,而不将相关嘚物理内存页返回给伙伴系统

在完成锁定之后调用)中扫描该链表,以找到相关项

unmap_vm_area 使用找到的vm_area 实例,从页表删除不再需要的项与分配内存时类似,该函数需要操作各级页表但这一次需要删除涉及的项。它还会更新CPU高速缓存

的所有元素,即指向所涉及的物理内存页嘚page 实例的指针然后对每一项调用__free_page ,将页释放到伙伴系统

最后,必须释放用于管理该内存区的内核外核状态数据结构

各个进程的虚拟哋址空间起始于地址0,延伸到TASK_SIZE - 1 其上是内核外核状态地址空间。在IA-32系统上地址空间的范围可达2 32 = 4 GiB总的地址空间通常按3:1比例划分,我们在下攵中将关注该划分内核外核状态分配了1 GiB,而各个用户空间进程可用的部分为3 GiB其他的划分比例也是可能的,但正如前文的讨论只能在非常特定的配置和某些工作负荷下才有用。

与系统完整性相关的非常重要的一方面是用户程序只能访问整个地址空间的下半部分,不能訪问内核外核状态部分如果没有预先达成“协议”,用户进程也不可能操作另一个进程的地址空间因为后者的地址空间对前者不可见。

无论当前哪个用户进程处于活动状态虚拟地址空间内核外核状态部分的内容总是同样的。取决于具体的硬件这可能是通过操作各用戶进程的页表,使得虚拟地址空间的上半部看上去总是相同的也可能是指示处理器为内核外核状态提供一个独立的地址空间,映射在各個用户地址空间之上

虚拟地址空间中包含了若干区域。其分布方式是特定于体系结构的但所有方法都有下列共同成分。

将文件内容映射到虚拟地址空间中的内存映射这个区域与vmalloc区域具有相同的属性,这个区域也会被划分为多个子区域每个子区域用一个struct vm_area_struct来描述。每佽创建一个新的内存映射时都会在内存映射区创建一个子区域。

内存映射区可以映射很多东西, 例如程序使用的动态库的代码. 后文会专门介绍内存映射.

内存映射区域的两种布局方式

下图给出了一个粗略的布局图, 其中省去了某些段, 使用这张图是为了解释内核外核状态中为什么會有2种地址空间布局:

text段如何映射到虚拟地址空间中由ELF标准确定每个体系结构都指定了一个特定的起始地址:IA-32系统起始于0x ,在text段的起始地址与最低的可用地址之间有大约128 MiB的间距用于捕获NULL 指针。其他体系结构也有类似的缺口:UltraSparc计算机使用0x

则起始点会减少一个小的随机量。設置PF_RANDOMIZE的主要目的是处于安全的考虑例如,使得攻击因缓冲区溢出导致的安全漏洞更加困难如果攻击者无法依靠固定地址找到栈,那么想要构建恶意代码通过缓冲器溢出获得栈内存区域的访问权,而后恶意操纵栈的内容将会困难得多。

每个体系结构都必须定义STACK_TOP 大多數都设置为TASK_SIZE ,即用户地址空间中最高的可用地址进程的参数列表和环境变量都是栈的初始数据。

每个体系结构都需要定义。几乎所有嘚情况下其值都是TASK_SIZE/3 。要注意如果使用内核外核状态的默认配置,则mmap区域的起始点不是随机的

如果计算机提供了巨大的虚拟地址空间,那么使用上述的地址空间布局会工作得非常好但在32位计算机上可能会出现问题。考虑IA-32的情况:虚拟地址空间从00xC0000000 GiB空间可供使用继续增长则会进入到mmap区域,这显然不是我们想要的

为了解决这个问题,在内核外核状态版本2.6.7开发期间引入一个新的虚拟地址空间布局(经典咘局仍然可以使用)新的布局如下图所示:

其想法在于使用固定值限制栈的最大长度。由于栈是有界的因此安置内存映射的区域可以在棧末端的下方立即开始。与经典方法相反内存映射区域现在是自顶向下扩展。由于堆仍然位于虚拟地址空间中较低的区域并向上增长洇此mmap区域和堆可以相对扩展,直至耗尽虚拟地址空间中剩余的区域为确保栈与mmap区域不发生冲突,两者之间设置了一个安全隙

各个体系結构可以通过几个配置选项影响虚拟地址空间的布局:

在创建新的内存映射时,除非用户指定了具体的地址否则内核外核状态需要找到一個适当的位置。如果体系结构自身想要选择合适的位置则必须设置预处理器符号HAVE_ARCH_UNMAPPED_AREA ,并相应地定义arch_get_unmapped_area 函数

在寻找新的内存映射低端内存位置时,通常从较低的内存位置开始逐渐向较高的内存地址搜索。内核外核状态提供了默认的函数arch_get_unmapped_area用于搜索但如果某个体系结构想要提供专门的实现,则需要设置预处理器符号HAVE_ARCH_GET_UNMAPPED_AREA

系统中的各个进程都具有一个struct mm_struct 的实例可以通过task_struct 访问。这个实例保存了进程的内存管理信息这個结构体非常庞大, 我们目前只看看这个结构体中与地址空间布局相关的部分:

可执行代码占用的虚拟地址空间区域,其开始和结束分别通过start_code end_code 标记

请注意,在ELF二进制文件映射到地址空间中之后这些区域的长度不再改变。

堆的起始地址保存在start_brk brk 表示堆区域当前的结束地址。盡管堆的起始地址在进程生命周期中是不变的但堆的长度会发生变化,因而brk 的值也会变

描述。两个区域都位于栈中最高的区域

3个え素都与内存映射区域相关, 将会在《管理子区域的红黑树和链表》中详细介绍

顾名思义, 存储了对应进程的地址空间长度. 该值通常是TASK_SIZE, ARM体系架構中,

如果在64位计算机上执行32位二进制代码,则task_size 描述了该二进制代码实际可见的地址空间长度

在使用load_elf_binary 装载一个ELF二进制文件时将创建进程嘚上述地址空间布局。exec 系统调用刚好使用了该函数加载ELF文件涉及大量纷繁复杂的技术细节,与我们的主旨关系不大因此下图给出的玳码流程图主要关注建立虚拟内存区域所需的各个步骤。

如果全局变量randomize_va_space 设置为1则启用地址空间随机化机制。通常情况下都是启用的但茬Transmeta

完成。如果对应的体系结构没有提供一个具体的函数则使用内核外核状态的默认例程,按上述布局建立地址空间但我们更感兴趣的昰,IA-32如何在经典布局和新的布局之间选择:

给出明确的指示或者要执行为不同的UNIX变体编译、需要旧的布局的二进制文件或者栈可以无限增长(最重要的一点)则系统会选择旧的布局,因为很难确定栈的下界亦即mmap区域的上界。

(其名称虽然带有arch 但该函数不一定是特萣于体系结构的,内核外核状态也提供了一个标准实现)用于自下而上地创建新的映射

在使用新布局时,内存映射自顶向下增长标准函数arch_get_unmapped_area_topdown (我不会详细描述)负责该工作。更有趣的问题是如何选择内存映射的基地址:

可以根据栈的最大长度来计算栈最低的可能位置,鼡作mmap区域的起始点但内核外核状态会确保栈至少跨越128 MiB的空间。另外如果指定的栈界限非常巨大,那么内核外核状态会保证至少有一小蔀分地址空间不被栈占据

如果要求使用地址空间随机化机制,上述位置会减去一个随机的偏移量最大为1 MiB。另外内核外核状态会确保該区域对齐到页帧,这是体系结构的要求

我们回到load_elf_binary 。该函数最后需要在适当的位置创建栈:

标准函数setup_arg_pages 即用于该目的因为该函数只是技術性的,我不会详细讨论该函数需要栈顶的位置作为参数。栈顶由特定于体系结构的常数STACK_TOP 给出而后调用randomize_stack_top ,确保在启用地址空间随机化嘚情况下对该地址进行随机偏移。

Linux下一切皆文件, 很多动态库(.so), 文本文件(.txt, ...), 还有很多其它数据都以文件的形式存放在磁盘上. 用户进程要想访问這些数据, 必须把这些数据拷贝到物理内存上, 然后把物理内存映射到用户进程的虚拟地址空间, 之后用户进程才可访问这些数据.

如前文《进程哋址空间的布局》所述, 在进程的虚拟地址空间中, 专门划分了一块区域, 用于上述映射, 这块区域就叫内存映射区.

不过实际的映射过程与上述步驟有些区别, 我们并不会先把文件的内容都拷贝到物理内存然后再做映射, 这样是不合理的: 假如有一个文件有1G的大小, 如果全部拷贝到物理内存僦会占用1G的内存大小, 很多时候物理内存根本就没有这么大; 而且在某个时刻, 我们只需要访问这个文件的一小部分内容, 没有必要把整个文件都拷贝到物理内存, 这是对物理内存的浪费!

因此, 实际的处理过程是先建立内存映射区和文件之间的映射(此时并不会拷贝任何数据到物理内存), 然后当程序访问到某个虚拟地址, 发现通过页表找不到对应的物理内存, 而且这个地址所在的区域已经被映射到某个文件, 此时系统才会向夥伴系统申请内存, 并拷贝需要的数据到内存(注意伙伴系统一次会分配一个PAGE_SIZE大小的内存, 因此每次拷贝动作至少也会拷贝PAGE_SIZE大小的内容). 负责申请物理页表并拷贝数据的是内核外核状态的缺页异常处理程序.

文件也有自己的地址空间, 所谓内存映射其实就是建立文件地址空间到內存映射区的映射. 注意一次映射不需要把整个文件的地址空间都映射过去, 这样会浪费内存映射区的虚拟地址空间, 我们可以只映射文件中我們需要的那一部分.

映射建立之后, 还必须解决一个问题: 当缺页异常产生之后, 如何读取文件中的内容? 文件数据在硬盘上的存储通常并不是连续嘚而且不同的文件读取的方式可能也不一样. 内核外核状态利用address_space 数据结构来抽象读取文件内容的方法, 不管是什么形式的文件, 在建立内存映射时, 都必须填充address_space中相关的接口, 以便后面读取文件中的内容.

另外, 尽管上述讨论是针对内存映射区, 但是对于进程地址空间的其它区域也同样适鼡, 例如进程的代码存储在磁盘上, 我们把代码文件映射到进程的代码区, 而且只有在执行某一部分代码时才把相应的内容拷贝进内存.

最后, 我们鼡一副图示来说明一下缺页异常的处理过程:

内核外核状态首先会检查异常地址是否合法(例如该地址是否属于某个内存映射区),

这些操作对用户进程是透明的。换句话说进程不会注意到页是实际在物理内存中,还是需要通过缺页异常加载

内存映射区会被划分为哆个子区域, 每个区域表示为vm_area_struct 的一个实例,其定义(简化形式)如下:

该子区域在进程虚拟地址空间中的起始位置

该子区域在进程虚拟地址涳间中的结束位置

用于链接所有的子区域, 链表中的子区域按地址递增的形式排好

mm_struct会用红黑树管理下属的所有子区域, vm_rb相当于红黑树中的┅个节点, 用于把本子区域集成到红黑树中

描述该区域的一组标志:

VM_SHARED 分别指定了页的内容是否可以读、写、执行或者由几个进程共享

VM_MAYSHARE 用於确定是否可以设置对应的VM_*标志。这是mprotect 系统调用所需要的

对于堆区域, 由于堆自下而上增长, 因此设置VM_GROWSUP

对于栈区域, 由于栈自顶向下增长, 故設置为VM_GROWSDOWN

对于内存映射区, 则根据实际情况设置

这两个标志用于提示内存管理子系统和块设备层,以优化其性能

通过进程的mm_struct结构体, 我们可以佷容易的找到属于该进程的所有子区域, 每个子区域都可能映射到某个文件, 因而也能很方便的知道一个进程映射了哪些文件

但是, 一个文件可能被映射到多个进程, 这种映射称之为共享映射, 例如C的标准库就可能被多个进程映射. 所以内核外核状态有时候需要知道一个文件或者文件中的某个区域被映射到了哪些进程.

shared就是用来解决这个问题的, shared.rb是红黑树的一个节点, 用于把该区域与映射的文件关联起来, 一个文件也用红黑樹来管理与它关联的所有子区域. 后文《文件的地址空间》中将会讨论更多细节

vm_ops 是一个指针, 指向许多方法的集合, 这些方法用于在区域上执荇各种标准操作

指定了文件映射的偏移量,该值用于只映射了文件部分内容时(如果映射了整个文件, 则偏移量为0)

偏移量的单位不是字节, 而是頁(即PAGE_SIZE . 这是合理的, 因为内核外核状态只支持以整页为单位的映射,

Linux系统中, 文件被打开一次, 就会产生与之相对的一个file实例.

vm_file指向file 实例描述叻一个被映射的文件

如果映射的对象不是文件则为NULL

vm_private_data 可用于存储私有数据,不由通用内存管理例程操作内核外核状态只确保在创建新区域时该成员初始化为NULL 指针。当前只有少数声音和视频驱动程序使用了该选项。

在创建和删除区域时, 分别调用open close . 这两个接口通常不使用,

fault 是非常重要的如果地址空间中的某个虚拟内存页不在物理内存中,自动触发的缺页异常处理程序会调用该函数

该函数将对应的数據读取到一个映射在用户地址空间的物理内存页中。

还有一些其他函数, 暂不一一介绍

管理子区域的红黑树和链表

我们知道struct mm_struct 很重要, 按前文的討论, 该结构提供了进程在内存中布局的所有必要信息.

另外, 它还包括下列成员, 用于管理用户进程的内存映射区域中所有的子区域:

mmap指向内存映射区的一个子区域, 每个子区域自身都有vm_next & vm_prev 指向相邻的子区域.

这样, 通过mmap, 我们就能遍历属于该进程的所有子区域.

注意所有区域按起始地址鉯递增次序被归入链表中

红黑树的跟节点, 属于该进程的每个子区域都通过struct rb_node vm_rb关联到这个根节点上.

红黑树是一种自平衡二叉查找树, 非常高效. 如果只通过链表管理子区域, 在有大量子区域时, 会导致查找某个特定子区域的效率很低, 因为这可能要扫描整个链表.

表示虚拟地址空间中用于内存映射的起始地址

调用get_unmapped_area 可以内存映射区域中为新映射找到适当的位置

最后我们用一张图来解释一下上述管理结构, 注意图的表示只是象征性的, 没有反映真实布局的复杂性.

每个打开文件(和每个块设备因为这些也可以通过设备文件进行内存映射)都表示为structfile 的一个实例, 该结构包含了一个指向文件地址空间struct

每个文件都有自己的地址空间, struct address_space表示. 一个文件可能被映射到多个进程中, 因此我们需要在address_space中记录本文件到底被映射到了哪些进程, 以便内核外核状态在有需要的时候获取该信息.

address_space结构体的细节如下, 我们暂时只关于与映射相关的部分:

都只存在一个inode实例.

我們就能找到对应的进程. 因此通过i_mmap, 我们就能找到所有映射了该文件的进程

该数据结构提供了获取文件内容的通用方法.

writepage 将一页的内容从物理内存写回到块设备上对应的位置, 以便永久地保存更改的内容

readpage 从潜在的块设备读取一页到物理内存中

内存映射区与文件地址空间建立关联

提供嘚标准实现连接起来,几乎所有的文件系统都使用了这种方式

在介绍API之前, 我们先介绍一下与内存映射区相关的操作, 因为API里面介绍的函数會引用这里的操作函数.

内存映射区其实就是进程的一段虚拟地址空间, 对该区域常用API有两个:

在上述两个API的基础上衍生出另外个操作:

或者在兩个区域中间插入一个新区域, 并且涉及的所有区域的访问权限相同,而且是从同一后备存储器映射的连续数据此时内核外核状态将涉及嘚区域合并为一个.

则必须据此截断现存的区域. 另外如果删除现存某个区域中间的一部分, 则必须把现存区域拆分为2个新的区域.

下图展示了区域合并与区域删除的示例:

下面, 我们分别介绍与这些操作相关的代码.

条件的第一个区域。该函数的参数不仅包括虚拟地址(addr)还包括一个指向mm_struct 实例的指针,后者指定了扫描哪个进程的地址空间

很多情况下, 我们都有可能连续几次操作同一个区域, 因此系统把上次操作的区域缓存起来, 加快处理速度.

用于从结点取出“有用数据”(在这里是vm_area_struct 实例)

如果某个区域结束地址大于目标地址而起始地址小于目标地址,内核外核状态就找到了一个适当的结点,可以退出while

则内核外核状态很容易判断何时结束搜索并返回NULL 指针作为错误信息

调用vmacache_update缓存找的区域, 因为下一佽find_vma 调用搜索同一个区域中邻近地址的可能性很高

在新区域被加到进程的地址空间时,内核外核状态会检查它是否可以与一个或多个现存区域合并vm_merge 在可能的情况下,将一个新区域与周边区域合并它需要很多参数。

分别是新区域的开始地址、结束地址、标志

pgoff 指定了映射在文件数据内的偏移量

实现的技术细节非常简单首先检查确定前一个区域的结束地址是否对应于新区域的起始地址。

倘若如此内核外核状態接下来必须检查两个区域,确认二者的标志和映射的文件相同文件映射内部的偏移量符合连续区域的要求,如果两个文件映射在地址涳间中连续但在文件中不连续,亦无法合并

通过can_vma_merge_after 辅助函数完成检查。将区域与前一个区域合并的工作看起来如下所示:

如果可以内核外核状态接下来检查后一个区域是否可以合并:

如果前一个和后一个区域都可以与当前区域合并,还必须确认前一个和

我要回帖

更多关于 内核外核状态 的文章

 

随机推荐