在上一篇博文里,我们已经看到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. 【dp】 poj 1953

    用n个数字0或者1组成一个排列,要求每两个1不相邻,问有多少种排法 dp[n][0]记录n个连续数,结尾为0的不同排列数dp[n][1]记录第n个连续数,结尾为1的不同排列数 DP公式: dp[i][ ...

  2. s-palindrome

    s-palindrome Let's call a string "s-palindrome" if it is symmetric about the middle of the ...

  3. backBarButtonItem无效

    控制器A push-> 控制器B, 我设置了B的backBarButtonItem为“返回”,发现无效... 原因: 应该在控制器A中设置backBarButtonItem,这样在push B之 ...

  4. linux 备份系统

    切换到root用户 切换到根目录 tar cvpzf backup.tgz --exclude=/proc --exclude=/lost+found --exclude=/backup.tgz -- ...

  5. HDU1425 <sort 快排>

    给你n个整数,请按从大到小的顺序输出其中前m大的数. 每组测试数据有两行,第一行有两个数n,m(0<n,m<1000000),第二行包含n个各不相同,且都处于区间[-500000,5000 ...

  6. 自行修改android.jar使其包含隐藏api

    1) 从指定版本的rom内获取到framework.jar 2) 解压framework.jar和android sdk内的android.jar 3) 将framework.jar解出来的东西拷到a ...

  7. python标准库-日志logging

    1.模块级别 先看一下logging模块的日志级别特点,共分6个等级. 可以手工设置当前日志的默认等级(warn),当日志输出的等级高于默认等级时,日志输出到屏幕,否则不输出. #!/usr/bin/ ...

  8. mysql时间函数,总是记不住,总是查。

    http://www.cnblogs.com/zeroone/archive/2010/05/05/1727659.html UNIX_TIMESTAMP() UNIX_TIMESTAMP(date) ...

  9. posix第二篇-----linux 锁机制

    1 简介 锁机制(lock) 是多线程编程中最常用的同步机制,用来对多线程间共享的临界区(Critical Section) 进行保护. Pthreads提供了多种锁机制,常见的有: 1) Mutex ...

  10. IOS中集合视图UICollectionView中DecorationView的简易使用方法

    转载自:   http://www.it165.net/pro/html/201312/8575.html Decoration View是UICollectionView的装饰视图.苹果官方给的案例 ...