Linux中的虚拟地址、物理地址和内存管理方式(一)

一、简单介绍下早期的内存实现:(可略过)

1、在早期的计算机中,运行一个程序的特点是:

(1)会把这些程序全都装入内存,

(2)程序都是直接运行在内存上的,也就是说程序中访问的内存地址都是实际的物理内存地址。

2、在早起的内存实现方式中出现的问题:

(1)当计算 机同时运行多个程序时,必须保证这些程序用到的内存总量要小于计算机实际物理内存的大小。

(2)进程地址空间不隔离。进程间可以相互修改数据

(3)内存使用率低。运行一个进程,必须在内存中为它分配实际进程大小的空间(不管当前这些空间是否都会用到)

(4)程序运行的地址不确定。分配内存时,只是单纯的从内存空间找一个足够满足进程要求的空间,所以进程运行的地址具有随机性。

二、虚拟地址技术

为了解决上面的问题,一些大牛们就提出了传说中的虚地址技术。即:在用户进程和实际的物理内存之间加一个中间层(虚拟地址),让用户进程只能访问虚拟地址,并且把虚拟地址物理地址转换的实现交给操作系统。

采用虚拟地址的特点:

1、当创建进程时,

(1)OS会为每个进程分配一个4G大小的虚拟地址空间,且每个进程都有3G的用户空间和1G的内核空间。但最后这1G的内核空间中的内容对于不同进程来说是一样的(之所以是4G大小,是因为在32位操作系统中,一个指针的大小是4btyes,所以能访问的地址空间就是0x00000000~0xFFFFFFFF == 4G)。

(2)这4G的虚拟地址空间是操作系统虚拟出来的,并不是真实存在的。

(3)每个进程只能访问自己的虚拟地址,无法访问别的进程的虚拟地址。

(4)虽然每个进程的虚拟地址都有4G大小,但并不是这4G的地址都可以由用户任意使用。在Linux中,系统把虚拟地址划分成2个部分(如下图所示):

注:1、任意一个时刻,在一个CPU上只有一个进程在运行。所以对于此CPU来讲,在这一时刻,整个系统只存在一个4GB的虚拟地址空间,这个虚拟地址空间是面向此进程的。

当进程发生切换的时候,虚拟地址空间也随着切换。每个进程只有在运行的时候,其虚拟地址空间才被运行它的CPU所知。在其它时刻,其虚拟地址空间对于CPU来说,是不可知的。所以尽管每个进程都可以有4 GB的虚拟地址空间,但在CPU眼中,只有一个虚拟地址空间存在。虚拟地址空间的变化,随着进程切换而变化。

2、内核空间与物理内存空间的映射和用户空间与物理内存空间的映射方式是不同:

虽然内核空间占据了每个虚拟空间中的最高1GB字节,但映射到物理内存却总是从最低地址(0x00000000)开始的,之所以这么规定,是为了在内核空间与物理内存之间建立简单的线性映射关系。其中,3GB(0xC0000000)就是物理地址与虚拟地址之间的位移量,在Linux代码中就叫做PAGE_OFFSET。
                
我们来看一下在include/asm/i386/page.h头文件中对内核空间中地址映射的说明及定义:

#define __PAGE_OFFSET           (0xC0000000)
……
#define PAGE_OFFSET             ((unsigned long)__PAGE_OFFSET)
#define __pa(x)                 ((unsigned long)(x)-PAGE_OFFSET)
#define __va(x)                 ((void *)((unsigned long)(x)+PAGE_OFFSET))
对于内核空间而言,给定一个虚地址x,其物理地址为“x- PAGE_OFFSET”,给定一个物理地址x,其虚地址为“x+ PAGE_OFFSET”。

这里再次说明,宏__pa()仅仅把一个内核空间的虚地址映射到物理地址,

这种方法决不适用于用户空间,用户空间的地址映射要复杂得多,它通过分页机制完成。

(图一)4G虚拟地址空间的整体结构

(图二)内核空间分配图

(图三,地址分布图)

2、与虚拟地址相对的就是我们内存条实际的大小了。以本人PC为例:我用的是2G内存,那么实际的物理地址空间就是:0x00000000~0x1FFFFFFF

三、分段和分页

1、采用虚拟地址技术后出现的新问题是:虚拟地址和物理地址之间的映射方式。大牛们提出的解决方式就是分段、分页和段页式了。具体实现我们用一个例子来演示:

eg:假设有两个进程 A 和 B ,进程 A 所需内存大小为 10M ,其虚拟地址空间分布在 0x00000000 到 0x00A00000 ,进程 B 所需内存为 100M ,其虚拟地址空间分布为 0x00000000 到 0x06400000 。

(1)采用分段的方式

这种分段的映射方法虽然解决了上述中的问题(2)和问题(4),但并没能解决问题(1)(3),即内存的使用效率问题。在分段的映射方法中,每次换入换出内存的都是整个程序, 这样会造成大量的磁盘访问操作,导致效率低下。所以这种映射方法还是稍显粗糙,粒度比较大

(2)采用分页式

分页的基本方法是,将地址空间分成许多的页。每页的大小由 CPU 决定,然后由操作系统选择页的大小。目前 Inter 系列的 CPU 支持 4KB 或 4MB 的页大小,而 PC 上目前都选择使用 4KB 。按这种选择, 4GB 虚拟地址空间共可以分成 1048576 个页, 512M 的物理内存可以分为 131072 个页。

分页的思想是程序运行时用到哪页就为哪页分配内存,没用到的页暂时保留在 硬盘上。

四、这里对分段、分页只做了一个简单笼统的介绍,如果想更深入的理解底层的实现机制,请看下一篇

Linux中的虚拟地址、物理地址和内存管理方式(二)

(0)

相关推荐

  • 计算机操作系统原理

    最近准备i面试,抽时间回顾一下计算机操作系统原理.  -2018.10.1 1.硬件基础 计算机的构成: 处理器(CPU):主要包括运算器.控制器 内存(主存储器) 输入输出设备 详细的讲,CPU内部 ...

  • 解惑之所谓的最大2GB可用虚拟地址空间

    咱们先来一个陈述:虚拟内存和虚拟地址空间不是一回事儿. 可能有些人容易将这两个概念弄混,今天来说说. 虚拟地址空间描述了地址是如何被解析,每一个进程都有它自己独立的虚拟地址空间.一个进程使用了多少虚存 ...

  • 15分钟!一文帮小白搞懂操作系统之内存

    前言 操作系统是一门比较难啃的课程,同时操作系统知识对开发者们来说是十分重要,相信各位在学操作系统的时候,有太多的抽象难以理解的词汇与概念,把我们直接劝退,即使怀着满腔热血的心情学操作系统,不到 3 ...

  • 万字整理,肝翻Linux内存管理所有知识点

    Linux的内存管理可谓是学好Linux的必经之路,也是Linux的关键知识点,有人说打通了内存管理的知识,也就打通了Linux的任督二脉,这一点不夸张.有人问网上有很多Linux内存管理的内容,为什 ...

  • Linux 内存管理之vmalloc

    走进vmalloc 根据前面的系列文章,我们知道了buddy system是基于页框分配器,kmalloc是基于slab分配器,而且这些分配的地址都是物理内存连续的.但是随着碎片化的积累,连续物理内存 ...

  • Linux 内存管理之CMA

    什么是CMA CMA是reserved的一块内存,用于分配连续的大块内存.当设备驱动不用时,内存管理系统将该区域用于分配和管理可移动类型页面:当设备驱动使用时,此时已经分配的页面需要进行迁移,又用于连 ...

  • linux中服务(service)管理

    一.介绍 服务(service) 本质就是进程,但是是运行在后台的,通常都会监听某个端口,等待其它程序的请求,比如(mysql , sshd 防火墙等),因此我们又称为守护进程,是Linux 中非常重 ...

  • 【原创】(十)Linux内存管理 - zoned page frame allocator - 5

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  • Linux之free命令内存管理功能使用及案例

    测试用例1: [root@iZ25ja2kaemZ ~]# free --help free: invalid option -- '-' usage: free [-b|-k|-m|-g] [-l] ...

  • 【原创】(十四)Linux内存管理之page fault处理

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  • 【原创】(十五)Linux内存管理之RMAP

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  • 【原创】(十六)Linux内存管理之CMA

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...