浅议windows内存管理[来自网络]

来源:互联网 发布:打开的软件关不掉 编辑:程序博客网 时间:2024/05/22 14:25

来源:网络

这里仅是对windows内存的简单介绍,适合编写windows应用程序的人阅读,主要参考《windows核心编程》及《深入解析windows操作系统》第四版。对windows内存管理的内部机制,将在以后加以介绍。
首先,用户用到的内存都是虚拟内存,windows内存管理器负责将虚拟地址转译成物理内存。对于32位机器,虚拟地址空间就是4G大小,用4个byte就可以覆盖,因此,32位机的指针大小就是4个字节。
在这4G的地址空间中,windows把它一分为二,高2G的地址空间属于操作系统(内核)使用,低2G归用户模式(即用户进程可以访问)。当然,可以用/3GB开关,将操作系统压缩到高1G,低3G归用户模式。通过这个划分,操作系统将自己与用户进程隔离,用户进程不能直接访问操作系统地址空间(高2G),从而将操作系统保护起来。另外,每个用户进程拥有自己的地址空间,即每个用户进程所使用的低2G空间,仅为自己可见。举个例子,进程a的地址0x00E39BA4所存放的数据,跟进程b的0x00E39BA4数据,不是同一个数据。这样,进程与进程隔离开,保证了进程的独立性。因此,我们可以这样理解,每个进程都拥有自己低2G的虚拟地址,高2G的地址空间归操作系统使用。假如一个进程运行失败,它既不会使操作系统瘫痪,也不会导致其他进程无法运行,操作系统简单的把这个用户进程杀死即可。关于操作系统地址空间如何划分和使用,以及用户进程间如何通信,将在以后的文章中给出。
后面,我将着重介绍用户进程的虚拟地址空间的分布以及使用,然后,再向大家介绍下编程常用的“堆栈”。
以win2000为例,如下图

 用户进程的虚拟地址空间的分布

从低位向高位看,首先是NULL指针分配的分区。编程中,为了防止出现野指针,我们把该指针赋为NULL,就是让指针指向这个区域。如果线程试图根据指针来读取或写入该区域,就会引发一个访问违规。这个分区非常有用,它有助于我们发现程序中的错误。
然后是DOS/16位Windows应用程序兼容分区,这个我们暂切不必考虑。
然后是用户方式分区,这是我们用的最多的一块区域。用户进程的代码、数据均放在该区域中。
再后面是禁止进入区,此区用于将用户区与内核区隔离。
最后就属于内核区了,本文暂不介绍。

看到这里,大家对用户进程的虚拟地址空间已经有了一个大体的概念,下面我们来介绍怎样操作虚拟内存。
在最初,我们认为整个2G空间都是空的。当进程加载并创建成功的时候,有一部分虚拟内存空间已经被使用了,还有一部分是空的。那么,我们可以通过WindowsApi来申请和使用这些空闲区域。在使用这块内存前,需要有两个操作,一个称作保留,一个称作提交。先介绍下保留,保留的意思,就是说,这块内存区域已经有人要了,但是,这块内存区域到底有没有映射的存储器呢?如果你初次保留,是没有被映射的。提交,就是将物理存储器映射到内存地址空间。举个例子,某市刚新建了一个1000米的路段,路段两旁已经建了一些建筑,但还有很大一部分是空的,现在需要规划、建设一些新项目,这些项目的生杀大权归建设局局长管。包工头a跟局长说,“我要在30米处建一座大楼,长10米”,局长说,“好,我划给你”,然后在笔记本上记录了下来。这块土地已经划给包工头a,但是包工头a还没有拿到合同证书,没有进入实质性阶段,所以还不能直接使用这块土地。这个过程就是保留。后来包工头拿到合同证书,正式拥有了这块土地,这就是提交。应该注意的是,物理存储器指的并不是物理内存,而是物理内存跟页文件(用于虚拟内存的硬盘空间)。保留内存区域,用VirtualAlloc;显式提交,也用VirtualAlloc,只是有所参数不同。在使用完后可以用VirtualFree来释放该内存区域。
到这里,我们已经知道如何直接申请和释放虚拟内存区域了。其实,在写程序时,我们用到最多的是堆栈了,下面将就这部分内容展开讨论。
堆栈包括两部分,堆和栈。每个进程都至少会有一个堆,在创建进程的时候已经建立好了,堆是进程所有的,也就是说,进程的所有线程会共用一个堆,当然,你也可以自己创建辅助堆。栈呢,是线程所有,每创建一个线程,系统就会为这个线程保留一个栈。现在我们分别来讨论。
首先,介绍下栈。创建“线程”时,系统已经为栈“保留”一段内存区域,win2000中栈的默认大小是1M,通常,栈会放在较低的虚拟地址上,比如0x080XXXX。栈的使用,是从高位向低位分配的,比如栈的区域为0x08000000-0x080FF000,那么最先申请的局部变量放在0x080FF000的位置,然后依次往低处放,直到0x08000000处。0x08000000处是一个守护页面,如果访问该页面,将引发一个异常,即栈溢出所至。另外,栈中还有一个带保护属性的页面,该页面是栈中已分配(提交)内存的最后一个页面。栈中存放函数的局部变量,当函数退出时,栈会退,也就是那个保护属性页面会往回退,那么,存放原先函数局部变量的内存页面已经无效,不能被访问了。因此,局部变量不用写程序来显式释放。
下面再说说进程的堆。当创建“进程”时,系统会“保留”一段地址空间归堆使用,win2000中堆默认大小是1M。堆是由堆管理器来维护的,当我们用new或malloc向堆管理器发出请求时,堆管理器会从堆中分出一块内存区域并返回。刚才说了,堆默认初始大小是1M,那么当我们从堆中申请的内存超过了1M,堆管理器会怎样处理呢。它会通过调用VirtualAlloc,来向内存管理器申请虚拟内存。另外,堆是所有线程共用的,当写一个单线程程序时,不会有什么问题,如果是多线程,那么就存在一个线程同步的问题。在用vc进行编译的时候,如果选用多线程运行期库,那么,我们所调用的new或malloc就是一个加锁的方法,这样就能安全正确的使用堆。new完之后我们就可以使用这块内存了,当不再使用时,我们必须通过delete或free来显式释放它,否则,直到进程结束前,这块内存会一直存在。
至此,本文的主要内容,虚拟地址空间,堆栈,就已经介绍完了。
可能有人会有这样的疑问,用VirtualAlloc和VirtualFree可以申请和释放虚拟内存,我们凭什么使用new和delete或malloc和free呢?为了解答这个问题,先介绍下地址空间的内存页面分配粒度。迄今为止,windows环境下,其分配粒度大小均为64k。那么,我们可以把整个虚拟内存空间看作是由一个个以64k为边界的64k大小的内存页面组成。如果用VirtualAlloc来申请内存,不管申请多大,内存管理器都会把整张整张的页面给你,即使你只申请一个字节的内存,内存管理器也会把一个64k大小的未用的页面返回给你。这样势必会造成内存资源的浪费。而调用new来申请堆中的空间,就不会出现这种情况。堆就是一个内存池,微软已经对堆管理器分配堆内存的策略做了高度的优化。当我们调用new或malloc时,堆管理器会从堆中找出一块恰当的内存返回给我们。因此,还是建议大家使用new来申请内存。
 
 
 
---> ---> ---> ---> --->

《c程序的存储空间布局》
 
首先要说明的是字节顺序问题。由于历史原因,计算机的数据在内存中的存放方式有两种:
little endian,big endian。intel 的X86系列使用little endian体系,其他基于Risc的mips计算机
使用big endian体系。
little endian 指的是数据的高字节存在内存的高地址上,低位字节存放在内存的低地址上,big endian
和它相反。当编写跨平台和网络程序时应该注意字节顺序。
下面给出一般的c程序存储布局:
用户空间的程序使用低2G的虚拟内存,内核空间使用高2G
高地址    ——0x7FFFFFFF———
                命令行参数和环境变量
                 ——————————
                 栈空间,向下增长
             ___________________
                堆空间,向上增长
            ———————————
                 未初始化的数据
           ———————————
                已初始化的数据
         ———————————
               正文段
低地址—0x00000000————
正文段:cpu执行的机器指令部分
初始化数据段:已初始化的全局变量
未初始化数据段:也成为bss段,存放没有初始化的全局变量
栈:自动变量,函数调用的返回地址,调用者环境变量,临时变量。
堆:动态分配的变量。
参考文献:
Advanced programming in the UNIX Environment , First Edition  :by W.Richard Steves
Microsoft Windows Internals ,Fourth Edition :by Mark E. Russinovich, David A. Solomon
 
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/yifeng123/archive/2007/07/02/1675727.aspx
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 运动完感觉很累怎么办 跑步后感觉很累怎么办 输液多了伤脾胃怎么办 运动完后特别晕怎么办 运动过量大腿肌肉酸痛怎么办 13岁发烧38.2度怎么办 头晕恶心想吐四肢无力怎么办 烧退了浑身疼怎么办 下午睡久了头疼怎么办 一天睡久了头疼怎么办 在家躺久了头疼怎么办 4周多儿童睡眠差怎么办 6岁儿童睡眠差怎么办 四年级的孩子不会写作文怎么办 四年级的孩子写不出作文怎么办? 欠了三万网贷怎么办 打完篮球浑身疼怎么办 在部队当兵意外死亡了怎么办 派派没有体力瓶怎么办 e记账登录不上怎么办 洁净净化区湿度高怎么办 政府测量土地少算了面积怎么办 北京武警欠我钱怎么办 被小混混打了怎么办 农保地建房子怎么办 WOW7.3到8.0橙装怎么办 90后离婚有孩子怎么办 90后的我们该怎么办 越南和中国结婚怎么办结婚证 改革怎么看走留怎么办事业怎么干 改革怎么看走留怎么办工作怎么干 军改怎么看我该怎么办 改革怎么办我该怎么干 改革怎么看 走留怎么办 腿又粗又弯怎么办 假发发量太多了怎么办 剃了发际线后悔怎么办 在外面遇到坏人抢劫怎么办 请事假单位不批怎么办 捷普请假不批怎么办 钉钉请假不审批怎么办