在上一篇博文里,我们已经看到Linux如何有效地利用80x86的分段和分页硬件单元把逻辑地址转换为线性地址,在由线性地址转换到物理地址。那么我们的应用程序如何使用这些逻辑地址,整个内存的地址布局又是怎样的?打一个比方,内存就像一座城市,而居住在这个城市里的市民就像是各个进程,一个市民吃喝拉撒睡,当然就得用于“房子”、“车子”、“票子”等各种各样的资源。有些资源是固定的,如“房子”,我们称之为静态数据;有些资源是动态的,如“车子”,我们称之为动态数据;有些资源是用来购买(产生)数据的,如“票子”,我们称之为代码。

现在,我们就来看看内存这座巨大的城市史如何布局的。在系统初始化阶段,内核首先在实模式下建立一个物理地址映射来指定哪些物理地址范围对内核可用而哪些不可用(主要是根据映射硬件设备I/O的共享内存,或者根据相应的页框含有的BIOS数据)。

内存的某些部分将永久地分配给BOIS或内核,用来存放BIOS信息、内核代码以及静态内核数据结构。所以内核将下列页框记为保留:
• 在不可用的物理地址范围内的页框,一般用来存放BIOS信息。
• 含有内核代码和已初始化的数据结构的页框。

标记为保留页框中的页,绝不能被动态分配或交换到磁盘上。

一般来说,Linux内核安装在RAM中从物理地址0x00100000开始的地方,也就是说,从第二个MB开始。所需页框总数依赖于内核的配置方案:典型的配置所得到的内核可以完全被安装在小于3MB的RAM中。

为什么内核没有安装在RAM第一个MB开始的地方?主要是为具体的PC体系结构所考虑。例如:
• 页框0由BIOS使用,存放加电自检(Power-On Self-Test,POST)期间检查到的硬件配置。因此,很多膝上型电脑的BIOS甚至在系统初始化后还将数据写到该页框。
• 物理地址从0x000a0000 到 0x000fffff的范围通常留给BIOS例程,并且映射ISA图形卡上的内部存储器。这个区域就是所有IBM兼容PC上从640KB到1MB之间著名的洞:物理地址存在但被保留,对应的页框不能由操作系统使用。
• 前1MB内的其他页框可能由特定计算机模型保留。例如,IBM 笔记本电脑把0x0a页框映射到0x9f页框。

在启动过程的早期阶段,内核询问BIOS并了解物理内存的大小,并调用machine_specific_memory_setup()函数建立物理地址映射。假设我们的内存是128MB,那么,第一个MB就给BIOS了。整个128MB的内存被物理映射成以下布局:
0x00000000   -   0x0009ffff     除第一个页框外的640K空间可用
0x000a0000   -   0x000effff     保留
0x000f0000   -   0x000fffff     保留给BIOS例程
0x00100000   -   0x07feffff     126.9MB可用空间
0x07ff0000   -   0x07ff2fff     ACPI data
0x07ff3000   -   0x07ffffff     ACPI NVS
0xffff0000   -   0xffffffff     保留
这里简单介绍一下128MB内存的末尾,从0x07ff0000 到0x07ff2fff的物理地址范围中存有加电自测(POST)阶段由BIOS写入的系统硬件设备信息;在初始化阶段,内核把这些信息拷贝到一个合适的内核数据结构中,然后认为这些页框是可用的。相反,从0x07ff3000到0x07ffffff的物理地址范围被映射到硬件设备的ROM芯片。从0xffff0000开始的物理地址范围标记为保留,因为它由硬件映射到了BIOS的ROM芯片。注意BIOS也许并不提供一些物理地址范围的信息(在上述图中,范围是0x000a0000到 0x000effff)。为安全可靠起见,Linux假定这样的范围是不可用的。

虽然,我们看到第一个MB里,BIOS并没有用完,但是为了避免把内核装入一组不连续的页框里,影响性能,Linux便跳过第1MB的RAM,之间从第2个MB开始加载。其实一般来说,对于两个MB,也就是512个页框,对初始化时的内核代码及一些静态数据,已经足够了。

内核可能不会见到BIOS报告的所有物理内存:例如,如果未使用PAE支持来编译,即使有更大的物理内存可供使用,内核也只能寻址4GB大小的RAM。setup_memory()函数在machine_specific_memory_setup()执行后被调用:它分析物理内存区域表并初始化一些变量来描述内核的物理内存布局,这些变量如下表所示:

变量名称

说明

num_physpages

最高可用页框的页框号

totalram_pages

可用页框的总数量

min_low_pfn

RAM 中在内核映像后第一个可用页框的页框号

max_pfn

最后一个可用页框的页框号

max_low_pfn

被内核直接映射的最后一个页框的页框号(低地址内存)

totalhigh_pages

内核非直接映射的页框的总数(高地址内存)

highstart_pfn

内核非直接映射的第一个页框的页框号

highend_pfn

内核非直接映射的最后一个页框的页框号

下图显示Linux怎样填充前3MB的RAM。
 
我们看到图中可用的页框,是内存的其余部分,我们称为动态内存,这不仅是进程所需的宝贵资源,也是内核本身所需的宝贵资源。实际上,整个系统的性能取决于如何有效地管理动态内存。因此,现在所有多任务操作系统都在尽力优化对动态内存的使用,也就是尽可能做到当需要是分配,不需要时释放。

后面的博文中,我们将重点讨论内核如何给自己分配动态内存。主要包括页框管理、高端内存映射、伙伴系统算法、slab分配器、内存池、非连续内存区管理。

Linux内存布局的更多相关文章

  1. Linux 内存布局

         本文主要简介在X86体系结构下和在ARM体系结构下,Linux内存布局的概况,力求简单明了,不过多深入概念,多以图示的方式来记忆理解,一图胜万言. Technorati 标签: 内存 布局 ...

  2. linux 内存布局以及tlb更新的一些理解

    问题: 1.内核线程是否有vma线性区? 2.单线程的一个进程,它修改了自己的页表,是否需要发送ipi来通知其他核更新tlb? 3.普通进程,在32位和64位,对应的线性区的最大地址能到多少? 在64 ...

  3. linux内存布局------深入理解计算机系统

  4. linux系统进程的内存布局

    内存管理模块是操作系统的心脏:它对应用程序和系统管理非常重要.今后的几篇文章中,我将着眼于实际的内存问题,但也不避讳其中的技术内幕.由于不少概念是通用的,所以文中大部分例子取自32位x86平台的Lin ...

  5. linux内存管理解析1----linux物理,线性内存布局及页表的初始化

    主要议题: 1分页,分段模式及实模式 2Linux分页 3linux内存线性地址空间布局及物理内存空间布局 4linux页表初始化及代码解析 1.1.1内存寻址和保护模式 在X86平台上,内存控制单元 ...

  6. [内存管理]linux X86_64处理器的内存布局图

    linux X86 64位内存布局图

  7. Linux内存管理 (3)内核内存的布局图

    专题:Linux内存管理专题 关键词:内核内存布局图.lowmem线性映射区.kernel image.ZONE_NORMAL.ZONE_HIGHMEM.swapper_pg_dir.fixmap.v ...

  8. Linux内存初始化(三) 内存布局

    一.前言 同样的,本文是内存初始化文章的一份补充文档,希望能够通过这样的一份文档,细致的展示在初始化阶段,Linux 4.4.6内核如何从device tree中提取信息,完成内存布局的任务.具体的c ...

  9. Linux进程地址空间 && 进程内存布局[转]

    一 进程空间分布概述       对于一个进程,其空间分布如下图所示: 程序段(Text):程序代码在内存中的映射,存放函数体的二进制代码. 初始化过的数据(Data):在程序运行初已经对变量进行初始 ...

随机推荐

  1. Spring + iBATIS完整示例

    最近研究了一下Spring + iBATIS.发现看别人的例子是一回事,自己写一个完整的应用又是另外一回事.自己受够了网上贴的一知半解的代码. iBATIS是一个持久化框架,封面了sql过程,虽然sq ...

  2. 救援行动(save)

    救援行动(save) 题目描述 Angel被人抓住关在一个迷宫了!迷宫的长.宽均不超过200,迷宫中有不可以越过的墙以及监狱的看守.Angel的朋友带了一个救援队来到了迷宫中.他们的任务是:接近Ang ...

  3. UML基础概念(转)

    UML基础概念 UML概述 uml简介 uml(unified Modeling Language )为面向对象软件设计提供统一的.标准的.可视化的建模语言.适用于描述以用例为驱动,以体系结构为中心的 ...

  4. Git 学习资源

    在线教程 Try Git: Git初学者绝不能错过的Git上手资源. 廖雪峰Git教程: 比较系统的中文在线教程 易百Git教程 : 另一个比较全的中文在线教程 Git Immersion : A V ...

  5. docker k8s 1.3.8 + flannel

    docker k8s + flannel kubernetes 是谷歌开源的 docker 集群管理解决方案. 项目地址: http://kubernetes.io/ 测试环境: node-1: 10 ...

  6. git分支综述

    对git不是很熟悉,有个问题要弄清楚一下. 假如远程仓库有 dev 和 master 两个分支,master 作为一个稳定版分支,可用于直接发布产品,日常的开发则 push 到 dev 分支,那我本地 ...

  7. C#读取word文件

    第一步:添加对在项目引用里添加上对Microsoft Word 11.0 object library的引用.右击--引用---在com标签下添加.

  8. IO口输入输出模式理解

    1.IO输入输出模式 2.有上拉,下拉,弱上拉,推挽,开漏输出:不同的单片机有不同的输出模式 3.以最简单的51单片机为例 P0:开漏型双向IO口,通常需要添加外部上拉电阻 P1~P3:准双向IO口, ...

  9. PHP 删除非法UTF-8字符

    //reject overly long 2 byte sequences, as well as characters above U+10000 and replace with ? $some_ ...

  10. 用Quick Cocos2dx做一个连连看(三)

    做个日记吧. 最近比较忙,斗志也不高,昨天有点时间了,开始做了一下连接方法,一开始用的搜索算法,但是bug比较多,究其原因是对语法和算法都不是很熟悉. 然后昨天下午利用点时间用稍微通俗一点的连接算法, ...