系统虚拟内存的理解 转载自http://blog.csdn.net/do2jiang/article/details/4690967

在进入正题前先来谈谈操作系统内存管理机制的发展历程,了解这些有利于我们更好的理解目前操作系统的内存管理机制。

早期的内存分配机制

在 早期的计算机中,要运行一个程序,会把这些程序全都装入内存,程序都是直接运行在内存上的,也就是说程序中访问的内存地址都是实际的物理内存地址。当计算 机同时运行多个程序时,必须保证这些程序用到的内存总量要小于计算机实际物理内存的大小。那当程序同时运行多个程序时,操作系统是如何为这些程序分配内存 的呢?下面通过实例来说明当时的内存分配方法:

某台计算机总的内存大小是 128M ,现在同时运行两个程序 A 和 B , A 需占用内存 10M , B 需占用内存 110 。计算机在给程序分配内存时会采取这样的方法:先将内存中的前 10M 分配给程序 A ,接着再从内存中剩余的 118M 中划分出 110M 分配给程序 B 。这种分配方法可以保证程序 A 和程序 B 都能运行,但是这种简单的内存分配策略问题很多。

图一

早期的内存分配方法

问题
1
:进程地址空间不隔离。由于程序都是直接访问物理内存,所以恶意程序可以随意修改别的进程的内存数据,以达到破坏的目的。有些非恶意的,但是有
bug
的程序也可能不小心修改了其它程序的内存数据,就会导致其它程序的运行出现异常。这种情况对用户来说是无法容忍的,因为用户希望使用计算机的时候,其中一个任务失败了,至少不能影响其它的任务。

问题
2
:内存使用效率低。在
A

B
都运行的情况下,如果用户又运行了程序
C
,而程序
C
需要
20M
大小的内存才能运行,而此时系统只剩下
8M
的空间可供使用,所以此时系统必须在已运行的程序中选择一个将该程序的数据暂时拷贝到硬盘上,释放出部分空间来供程序
C
使用,然后再将程序
C
的数据全部装入内存中运行。可以想象得到,在这个过程中,有大量的数据在装入装出,导致效率十分低下。

问题
3
:程序运行的地址不确定。当内存中的剩余空间可以满足程序
C
的要求后,操作系统会在剩余空间中随机分配一段连续的
20M
大小的空间给程序
C
使用,因为是随机分配的,所以程序运行的地址是不确定的。


分段

为 了解决上述问题,人们想到了一种变通的方法,就是增加一个中间层,利用一种间接的地址访问方法访问物理内存。按照这种方法,程序中访问的内存地址不再是实
际的物理内存地址,而是一个虚拟地址,然后由操作系统将这个虚拟地址映射到适当的物理内存地址上。这样,只要操作系统处理好虚拟地址到物理内存地址的映 射,就可以保证不同的程序最终访问的内存地址位于不同的区域,彼此没有重叠,就可以达到内存地址空间隔离的效果。

当创建一个进程时,操作系统会为该进程分配一个
4GB
大小的虚拟
进程地址空间。之所以是
4GB
,是因为在
32
位的操作系统中,一个指针长度是
4
字节,而
4
字节指针的寻址能力是从
0x00000000~0xFFFFFFFF
,最大值
0xFFFFFFFF
表示的即为
4GB
大小的容量。与虚拟地址空间相对的,还有一个物理地址空间,这个地址空间对应的是真实的物理内存。如果你的计算机上安装了
512M
大小的内存,那么这个物理地址空间表示的范围是
0x00000000~0x1FFFFFFF
。当操作系统做虚拟地址到物理地址映射时,只能映射到这一范围,操作系统也只会映射到这一范围。当进程创建时,每个进程都会有一个自己的
4GB
虚拟地址空间。要注意的是这个
4GB
的地址空间是“虚拟”的,并不是真实存在的,而且每个进程只能访问自己虚拟地址空间中的数据,无法访问别的进程中的数据,通过这种方法实现了进程间的地址隔离。那是不是这
4GB
的虚拟地址空间应用程序可以随意使用呢?很遗憾,在
Windows
系统下,这个虚拟地址空间被分成了
4
部分:
NULL
指针区、用户区、
64KB
禁入区、内核区。应用程序能使用的只是用户区而已,大约
2GB
左右
(
最大可以调整到
3GB)
。内核区为
2GB
,内核区保存的是系统线程调度、内存管理、设备驱动等数据,这部分数据供所有的进程共享,但应用程序是不能直接访问的。

人 们之所以要创建一个虚拟地址空间,目的是为了解决进程地址空间隔离的问题。但程序要想执行,必须运行在真实的内存上,所以,必须在虚拟地址与物理地址间建
立一种映射关系。这样,通过映射机制,当程序访问虚拟地址空间上的某个地址值时,就相当于访问了物理地址空间中的另一个值。人们想到了一种分段

(Sagmentation)
的方法,它的思想是在虚拟地址空间和物理地址空间之间做一一映射。比如说虚拟地址空间中某个
10M
大小的空间映射到物理地址空间中某个
10M
大小的空间。这种思想理解起来并不难,操作系统保证不同进程的地址空间被映射到物理地址空间中不同的区域上,这样每个进程最终访问到的

物理地址空间都是彼此分开的。通过这种方式,就实现了进程间的地址隔离。还是以实例说明,假设有两个进程
A

B
,进程
A
所需内存大小为
10M
,其虚拟地址空间分布在
0x00000000

0x00A00000
,进程
B
所需内存为
100M
,其虚拟地址空间分布为
0x00000000

0x06400000
。那么按照分段的映射方法,进程
A
在物理内存上映射区域为
0x00100000

0x00B00000
,,进程
B
在物理内存上映射区域为
0x00C00000

0x07000000
。于是进程
A
和进程
B
分别被映射到了不同的内存区间,彼此互不重叠,实现了地址隔离。从应用程序的角度看来,进程
A
的地址空间就是分布在
0x00000000

0x00A00000
,在做开发时,开发人员只需访问这段区间上的地址即可。应用程序并不关心进程
A
究竟被映射到物理内存的那块区域上了,所以程序的运行地址也就是相当于说是确定的了。

图二显示的是分段方式

的内存映射方法。

图二

分段方式的内存映射方法


种分段的映射方法虽然解决了上述中的问题一和问题三,但并没能解决问题二,即内存的使用效率问题。在分段的映射方法中,每次换入换出内存的都是整个程序,
这样会造成大量的磁盘访问操作,导致效率低下。所以这种映射方法还是稍显粗糙,粒度比较大。实际上,程序的运行有局部性特点,在某个时间段内,程序只是访
问程序的一小部分数据,也就是说,程序的大部分数据在一个时间段内都不会被用到。基于这种情况,人们想到了粒度更小的内存分割和映射方法,这种方法就是分页

(Paging)


分页

分页的基本方法是,将地址空间分成许多的页。每页的大小由
CPU
决定,然后由操作系统选择页的大小。目前
Inter
系列的
CPU
支持
4KB

4MB
的页大小,而
PC
上目前都选择使用
4KB
。按这种选择,
4GB
虚拟地址空间共可以分成
1048576
个页,
512M
的物理内存可以分为
131072
个页。显然虚拟空间的页数要比物理空间的页数多得多。

在 分段的方法中,每次程序运行时总是把程序全部装入内存,而分页的方法则有所不同。分页的思想是程序运行时用到哪页就为哪页分配内存,没用到的页暂时保留在
硬盘上。当用到这些页时再在物理地址空间中为这些页分配内存,然后建立虚拟地址空间中的页和刚分配的物理内存页间的映射。

下面通过介绍一个可执行文件的装载过程来说明分页机制的实现方法。一个可执行文件
(PE
文件
)
其实就是一些编译链接好的数据和指令的集合,它也会被分成很多页,在
PE
文件执行的过程中,它往内存中装载的单位就是页。当一个
PE
文件被执行时,操作系统会先为该程序创建一个
4GB
的进程虚拟地址空间。前面介绍过,虚拟地址空间只是一个中间层而已,它的功能是利用一种映射机制将虚拟地址空间映射到物理地址空间,所以,创建
4GB
虚拟地址空间其实并不是要真的创建空间,只是要创建那种映射机制所需要的数据结构而已,这种数据结构就是页目和页表。

当创建完虚拟地址空间所需要的数据结构后,进程开始读取
PE
文件的第一页。在
PE
文件的第一页包含了
PE
文件头和段表等信息,进程根据文件头和段表等信息,将
PE
文件中所有的段一一映射到虚拟地址空间中相应的页
(PE
文件中的段的长度都是页长的整数倍
)
。这时
PE
文件的真正指令和数据还没有被装入内存中,操作系统只是根据
PE
文件的头部等信息建立了
PE
文件和进程虚拟地址空间中页的映射关系而已。当
CPU
要访问程序中用到的某个虚拟地址时,当
CPU
发现该地址并没有相相关联的物理地址时,
CPU
认为该虚拟地址所在的页面是个空页面,
CPU
会认为这是个页错误
(Page Fault)

CPU
也就知道了操作系统还未给该
PE
页面分配内存,
CPU
会将控制权交还给操作系统。操作系统于是为该
PE
页面在物理空间中分配一个页面,然后再将这个物理页面与虚拟空间中的虚拟页面映射起来,然后将控制权再还给进程,进程从刚才发生页错误的位置重新开始执行。由于此时已为
PE
文件的那个页面分配了内存,所以就不会发生页错误了。随着程序的执行,页错误会不断地产生,操作系统也会为进程分配相应的物理页面来满足进程执行的需求。

分页方法的核心思想就是当可执行文件执行到第
x
页时,就为第
x
页分配一个内存页
y
,然后再将这个内存页添加到进程虚拟地址空间的映射表中
,
这个映射表就相当于一个
y=f(x)
函数。应用程序通过这个映射表就可以访问到
x
页关联的
y
页了。

总结:

32

位的CPU
的寻址空间是4G
,
所以虚拟内存的最大值为4G
,
而windows
操作系统把这4G
分成2
部分,
即2G
的用户空间和2G
的系统空间,
系统空间是各个进程所共享的,
他存放的是操作系统及一些内核对象等,
而用户空间是分配给各个进程使用的,
用户空间包括用:
程序代码和数据,
堆,
共享库,
栈。

时间: 2024-10-01 05:00:09

系统虚拟内存的理解 转载自http://blog.csdn.net/do2jiang/article/details/4690967的相关文章

推荐一些C#相关的网站、资源和书籍 (转载自http://blog.csdn.net/chinacsharper/article/details/17514923)

一.网站 1.http://msdn.microsoft.com/zh-CN/ 微软的官方网站,C#程序员必去的地方.那里有API开发文档,还有各种代码.资源下载. 2.http://social.msdn.microsoft.com/Forums/zh-CN/home 微软msdn论坛.定位于微软技术的传播和技术问题的解决,是学习微软技术的好去处. 3.http://www.codeproject.com/ 国外著名的社区网站,面向世界的程序员.有很多不错的程序都可以从那里下载到. 4.htt

Oracle RAC 全局等待事件 gc current block busy 和 gc cr multi block request 说明--转载(http://blog.csdn.net/tianlesoftware/article/details/7777511)

一.RAC 全局等待事件说明 在RAC环境中,和全局调整缓存相关的最常见的等待事件是global cache cr request,global cache busy和equeue. 当一个进程访问需要一个或者多个块时,Oracle会首先检查自己的Cache是否存在该块,如果发现没有,就会先通过global cache赋予这些块共享访问的权限,然后再访问.假如,通过global cache发现这些块已经在另一个实例的Cache里面,那么这些块就会通过Cache Fusion,在节点之间直接传递,

分享一篇文章C语言字节对齐问题(适用于C++)转载至http://blog.csdn.net/21aspnet/article/details/6729724

文章最后本人做了一幅图,一看就明白了,这个问题网上讲的不少,但是都没有把问题说透. 一.概念    对齐跟数据在内存中的位置有关.如果一个变量的内存地址正好位于它长度的整数倍,他就被称做自然对齐.比如在32位cpu下,假设一个整型变量的地址为0x00000004,那它就是自然对齐的.   二.为什么要字节对齐   需要字节对齐的根本原因在于CPU访问数据的效率问题.假设上面整型变量的地址不是自然对齐,比如为0x00000002,则CPU如果取它的值的话需要访问两次内存,第一次取从0x000000

C++ 运算符的重载(转载自http://blog.csdn.net/insistgogo/article/details/6626952)

(转载自http://blog.csdn.net/insistgogo/article/details/6626952) 什么是运算符的重载? 运算符与类结合,产生新的含义. 为什么要引入运算符重载? 作用:为了实现类的多态性(多态是指一个函数名有多种含义) 怎么实现运算符的重载? 方式:类的成员函数 或 友元函数(类外的普通函数) 规则:不能重载的运算符有 .  和 .* 和 ?: 和 ::  和 sizeof 友元函数和成员函数的使用场合:一般情况下,建议一元运算符使用成员函数,二元运算符使

Android音频系统之音频框架(转http://blog.csdn.net/uiop78uiop78/article/details/8796492)

1.1 音频框架 转载请注明,From LXS, http://blog.csdn.net/uiop78uiop78/article/details/8796492 Android的音频系统在很长一段时间内都是外界诟病的焦点.的确,早期的Android系统在音频处理上相比于IOS有一定的差距,这也是很多专业的 音乐播放软件开发商没有推出Android平台产品的一个重要原因.但这并不代表它的音频框架一无是处,相反,基于Linux系统的Android平台有 很多值得我们学习的地方. 1.1.1 Li

Win32消息循环机制等【转载】http://blog.csdn.net/u013777351/article/details/49522219

Dos的过程驱动与Windows的事件驱动 在讲本程序的消息循环之前,我想先谈一下Dos与Windows驱动机制的区别: DOS程序主要使用顺序的,过程驱动的程序设计方法.顺序的,过程驱动的程序有一个明显的开始,明显的过程及一个明显的结束,因此程序能直接控制程序事件或过程的顺序.虽然在顺序的过程驱动的程序中也有很多处理异常的方法,但这样的异常处理也仍然是顺序的,过程驱动的结构. 而Windows的驱动方式是事件驱动,就是不由事件的顺序来控制,而是由事件的发生来控制,所有的事件是无序的,所为一个程

xcode5.1.1安装iOS6.1模拟器 -----转载自http://blog.csdn.net/forestml2008/article/details/21714259

Xcode5.1默认不支持iOS5版本的模拟器开发调试,在OS X Mavericks(10.9.x)下默认只能支持iOS6.1及以上版本的模拟器,在OS X Mountain Lion(10.8.x)下默认只能支持iOS6.0及以上版本的模拟器进行开发和调试,在此条件之下的版本只能使用硬件设备进行开发调试.虽然现在低版本的iOS设备越来越少了,但是有时客户的需求可能会要求我们一定要兼容iOS5(或更低版本)及以上版本,如果我们手头找不到低版本硬件设备用于调试或者完全使用硬件设备而没有对应的模拟

Linux下socket编程(转载自http://blog.csdn.net/hguisu/article/details/7445768/)

Linux的SOCKET编程详解 1. 网络中进程之间如何通信 进 程通信的概念最初来源于单机系统.由于每个进程都在自己的地址范围内运行,为保证两个相互通信的进 程之间既互不干扰又协调一致工作,操作系统为进程通信提供了相应设施,如 UNIX BSD有:管道(pipe).命名管道(named pipe)软中断信号(signal) UNIX system V有:消息(message).共享存储区(shared memory)和信号量(semaphore)等. 他们都仅限于用在本机进程之间通信.网间进

matlab 降维工具 转载【https://blog.csdn.net/tarim/article/details/51253536】

降维工具箱drtool 这个工具箱的主页如下,现在的最新版本是2013.3.21更新,版本v0.8.1b http://homepage.tudelft.nl/19j49/Matlab_Toolbox_for_Dimensionality_Reduction.html 这里有两个这个工具箱的简单介绍: [Matlab]数据降维工具箱drtoolbox http://blog.csdn.net/xiaowei_cqu/article/details/7515077 [Dimensionality