在上一篇博文里,我们已经看到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. 服务器修改 ssh 22端口

    我们首先修改配置文件,让ssh 通知支持2个端口访问 ,22 和 23456 端口. Port 22 Port 23456 为什么要这样: 万一我用 23456端口替换了22端口,但是 23456正好 ...

  2. 【百度地图开发之二】基于Fragment的地图框架的使用

    写在前面的话: [百度地图开发之二]基于Fragment的地图框架的使用(博客地址:http://blog.csdn.net/developer_jiangqq),转载请注明. Author:hmji ...

  3. 使用python将mysql数据库的数据转换为json数据

    由于产品运营部需要采用第三方个推平台,来推送消息.如果手动一个个键入字段和字段值,容易出错,且非常繁琐,需要将mysql的数据转换为json数据,直接复制即可. 本文将涉及到如何使用Python访问M ...

  4. Microsoft Web Test Recorder在录制时没有显示

    在进行web test录制时,IE启动后,在左侧可能没有显示Microsoft Web Test Recorder,这很有可能是因为IE加载项中,该项被禁止了,按照如下操作可解决此问题: 1. 打开I ...

  5. Qt5:Qt程序不在任务拦显示图标

    setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint); 回头再写

  6. 第2课 Linux操作系统简介

    1. Linux操作系统的构成 (1)内核(kernel) ①操作系统的核心,负责管理系统的进程.内存.设备驱动程序.文件和网络系统. ②控制系统和硬件之间的相互通信. ③决定着系统的性能和稳定性. ...

  7. Chapter 1 First Sight——3

    Flying doesn't bother me; the hour in the car with Charlie, though, I was a little worried about. 坐飞 ...

  8. PHP :Call to undefined function mysql_connect()

    今天配置apache ,php,mysql 的时候,一直报(Call to undefined function mysql_connect()),PHP一直连接不上数据库,从网上查,答案也都是千篇一 ...

  9. 关于flex4 list 高度适应内容

    Flex 4: Setting Spark List height to its content height How to set a Spark List height to the height ...

  10. Java运行内存结构分析