windows的内存管理很是严谨,使用内存必须首先分配,当然每个操作系统都是这样,然而windows的严谨在于分配的过程,分为保留和提交两个阶段,其中保留的含义就是在进程的虚拟地址空间保留一块空间,不能用作他用,保留的概念是针对虚拟地址空间的,而提交的含义是将刚才保留的虚拟地址空间的虚拟内存块映射到物理内存,这里windows扩展了物理内存的含义,包括内存条代表的物理内存和磁盘页文件以及任何可以和真正的物理内存进行换入换出操作的后备存储,提交的概念其实就是一个映射,为了将虚拟内存变得可用而做的一个到实际物理存储的一个映射,就是将假的变真了。

windows的保留和提交两阶段方式涉及到几件事情,一个就是页表什么时候确立,我们可以设想一种合理的方式,就是在内存块保留的时候,不操作页表,仅仅将虚拟内存段插入到一个便于查找和插入,删除的数据结构中,而在提交阶段操作页表,当然此时内存不一定已经到了真正的物理内存,很有可能只在页文件中为之分配了一个slot而已,此情形下,页表的相关位就可以用来描述这个slot的位置以及别的信息,只要页表的存在位为0即可,这一点和linux可以一样,事实上,提交内存只是在扩展物理内存含义的前提下才表示映射物理内存,虚拟内存真正被映射到原始物理内存只有在该内存被访问的时候才会发生,这是绝对懒惰的。事实上我们可以看到windows的方式不够懒惰,linux没有保留和提交的概念,当一个执行绪调用mmap或者malloc或者brk等等不同层次的函数时,实际上就等于保留了内存区域,而只有在该内存被访问的时候,才会直接映射到物理内存而在这之前,根本不会将虚拟内存和物理的事实有任何联系,真对于假只有在不能再隐蔽事实的的时候才会显露,linux的内存管理是一种绝对的懒惰,访问内存其实就可以被看做内存提交。windows之所以采用这一种的方式来管理内存其实是为了用一种更加统一的方式去管理所有的内存,只要内存提交了,那么内存管理器就要跟踪这块内存,不管它在物理存储器还是在磁盘页文件。linux的方式看来更加不规范,linux使用页表来充当双面角色,既可以查找物理存储器又可以查找交换分区内存的位置,并且linux中没有一种机制来统一管理物理存储器和交换分区的空间,靠强大的文件系统功能和高效的内存管理和文件管理数据结构就可以轻易做到内存的高效换入换出,解除了物理存储器和交换分区的耦合,相反,在windows下,统一华丽的外表下扭曲着混乱不堪的繁杂,比如说如果想修改页文件的格式,那么必须涉及内存提交时的逻辑,而在linux中只需要换一个file_operations就可以了,统一华丽的外表完全不是仅仅带来了观感上的舒服,同样也付出了代价,比如平衡进程间内存数量的任务就交给了用户,其实用户只要可以在本进程内存分配和管理内存上保持高度灵活就可以了,进程间的内存平衡这样的任务显然是操作系统应该担负起来的,由于只要提交内存,或者在物理存储器或者在磁盘页文件会占据一定的空间,而这些空间是所有的进程共享的,如果一个进程疯狂的提交了过多的内存,那么别的进程就要忍饥挨饿,这一点上操作系统作为一个协调者实际上帮不上什么忙,顶多将贪婪者灭掉了事,物理内存在各个进程间的分配比例完全取决于进程自己而失去了别的进程的监督以及内核机制的协调,这一点看起来不如linux,在linux中内存管理模块尽量使内存在进程间公平的分配,即使一个进程自己分配了大量的内存,只要它不访问这些内存,这些内存连交换分区都不会占据更别说物理存储器了,当然如果这个贪婪的进程要是访问了这些内存,那结果就和windows一样了,从程序的行为应该很容易辨别出这个进程,不过不管怎样也比windows那种允许占着茅坑不拉屎的策略要好得多,虽然内存已经很便宜,但是对于同样增长的应用来讲内存仍然是稀缺资源,因此完全懒惰式的分配方式应该就是最节省的方式。

作为以上讨论的直接结果,我们来看一下两个系统中的堆栈。在windows中堆栈的分配是静态的,也就是说在PE文件中确定了线程堆栈的大小并且一般不能在运行时动态改变,在对堆栈进行管理的时候,windows使用了一种稍微复杂一点但是考虑的很周到的方法,windows尽力去保护自己的堆栈不会溢出,怎么保护呢?在《windows核心编程》上有详细的描述,大致就是说首先为你的堆栈确定一个大小,然后将这段如此大小的内存块的第一个和最后一个页面设置为保留,其余的页面遵循以下原则:假设堆栈向下增长,windows将依次把正在被使用的下一个页面设置为保护提交,当然正在被使用的页面肯定是提交的了,每当保护提交页面被访问时系统会得到通知,注意得到通知而不是出错信息,并没有什么严重的错误,因为保护提交页面可以被访问,它已经提交了,只不过由于具有保护属性,所有要告知系统这一件事,系统得知后可以将保护提交属性设置给后一个页面,依次类推,堆栈有着严格的顺序访问特性,就是说首先是高地址被访问,在略低的地址不被使用之前更低的地址不会被使用,当然除非你使用汇编语言完全脱离堆栈的概念,这样的话,线程的堆栈空间页面将按照从高到底的顺序一个个被提交,而紧接着被提交的页面将被设置为保护提交,直到最后,到达堆栈的末尾的时候,windows会检测到,此时不再将最后一个页面设置为保护提交,而是引发一个栈溢出异常。windows的这种机制的结果就是有效地保护了堆栈后面的数据不被堆栈数据覆盖,但是这种机制并不是每次都奏效的,比如一个足以使栈溢出的大数组分配在栈上,数组的起始其实已经出了堆栈,如果我直接存取这第一个元素的话,并且恰好该元素覆盖的内存已经被提交,那就完蛋了,如果你觉得上述实例会被编译器发现的话,那么考虑下面的例子: 
char s[1]; 
s -= 100000; 
*s = 100;

看看linux是怎么做的,很简单,十分懒惰,linux没有为堆栈分配静态的大小,而是利用缺页中断使得堆栈在运行期动态增长,当然没有了固定的大小也就不存在溢出的问题了,只要虚拟内存足够,动态增长的需求就有可能被满足,那么linux有没有什么办法来保护非堆栈数据被堆栈数据损坏或者反过来的情况呢?说实话,没有,主要是因为一来实现那个机制很复杂,维护引入的额外数据结构肯定会影响效率,二来这是用户空间的事情,程序员如果不合格直接开掉他就是了,内核不用为他擦屁股,实际上内核如果真的用雕虫小技帮他擦了屁股,没有会说内核很高明的,因此开源的linux没有这种复杂而且单单对内核没有什么用的机制,实际上如果程序员不合格,那么他写的程序是防不胜防的,机器能和人PK吗?很显然不能,再好的操作系统面对一般烂的程序员也是无力去爱谁啊!

最后讨论一下“如何分配内存以及在哪里分配到底要不要让用户看到”这个有点哲学味道的问题,这个问题关键要看分配的内存做什么用以及这种作用和系统机制的联系的紧密程度,比如说我需要一块内存保存一些我程序里面的结构,比如大型数据库缓冲,比如一个字符串,这种情况下分配越透明越好,因为程序没有必要和实现机制交流,这样程序可以更加集中精力解决所谓的业务问题,但是如果一块内存被一个管理机制需要,那么就有必要导出给用户更多的信息,因为这种需求往往都是关注实现本身的需求,而不是接口需求,比如线程栈的位置,因为线程是操作系统的一种机制,目的是优化程序执行,它其实和业务逻辑没有什么太大的关系,线程更多的被程序流程的管理机制使用而不是被业务流程使用。在这一点点上,linux要比windows好得多,看看clone系统调用的参数,用户必须为线程分配栈空间,而这在windows中却是被默默执行的,实际上windows尽力去向用户隐藏底层的很多重要的信息,然而类似线程栈的位置这样的信息很多用户空间的管理机制还是要用到的,因此最好将这一切都交给用户,系统不要管的太多。

转载于:https://www.cnblogs.com/dartagnan/archive/2011/06/15/2126880.html

windows和linux的内存管理相关推荐

  1. Linux堆内存管理深入分析(上)

    Linux堆内存管理深入分析 (上半部) 作者:走位@阿里聚安全   0 前言 近年来,漏洞挖掘越来越火,各种漏洞挖掘.利用的分析文章层出不穷.从大方向来看,主要有基于栈溢出的漏洞利用和基于堆溢出的漏 ...

  2. 转:浅谈Linux的内存管理机制

    一 物理内存和虚拟内存          我们知道,直接从物理内存读写数据要比从硬盘读写数据要快的多,因此,我们希望所有数据的读取和写入都在内存完成,而内存是有限的,这样就引出了物理内存与虚拟内存的概 ...

  3. 浅谈Linux的内存管理机制

    一 物理内存和虚拟内存          我们知道,直接从物理内存读写数据要比从硬盘读写数据要快的多,因此,我们希望所有数据的读取和写入都在内存完成,而内存是有限的,这样就引出了物理内存与虚拟内存的概 ...

  4. Linux系统内存管理之伙伴系统分析 - 旭东的博客 - 博客园

    Linux系统内存管理之伙伴系统分析 - 旭东的博客 - 博客园 Linux系统内存管理之伙伴系统分析 今天去面试,一位面试官提到了内存管理的伙伴系统,当时就懵了,因为根本就没有听说过.晚上回来在实验 ...

  5. Linux堆内存管理深入分析

    0 前言 近年来,漏洞挖掘越来越火,各种漏洞挖掘.利用的分析文章层出不穷.从大方向来看,主要有基于栈溢出的漏洞利用和基于堆溢出的漏洞利用两种.国内关于栈溢出的资料相对较多,这里就不累述了,但是关于堆溢 ...

  6. linux按进程分配物理内存,linux下内存管理学习心得(一)

    最近在学习内存管理的时候,发现对linux下的所谓内存如何管理如何分配都不熟悉,通过最近的查阅资料可总结如下,如有不妥之处欢迎大家批评与指正. 总的的来说linux的内存管理其实主要难理解的是以下几个 ...

  7. 【Linux 内核 内存管理】虚拟地址空间布局架构 ③ ( 内存描述符 mm_struct 结构体成员分析 | mmap | mm_rb | task_size | pgd | mm_users )

    文章目录 一.mm_struct 结构体成员分析 1.mmap 成员 2.mm_rb 成员 3.get_unmapped_area 函数指针 4.task_size 成员 5.pgd 成员 6.mm_ ...

  8. 【Linux 内核 内存管理】内存管理架构 ④ ( 内存分配系统调用过程 | 用户层 malloc free | 系统调用层 brk mmap | 内核层 kmalloc | 内存管理流程 )

    文章目录 一.内存分配系统调用过程 ( 用户层 | 系统调用 | 内核层 ) 二.内存管理流程 一.内存分配系统调用过程 ( 用户层 | 系统调用 | 内核层 ) " 堆内存 " ...

  9. 【Linux 内核 内存管理】内存管理架构 ② ( 用户空间内存管理 | malloc | ptmalloc | 内核空间内存管理 | sys_brk | sys_mmap | sys_munmap)

    文章目录 一.用户空间内存管理 ( malloc / free / ptmalloc / jemalloc / tcmalloc ) 二.内核空间内存管理 1.内核内存管理系统调用 ( sys_brk ...

最新文章

  1. Swift 开源带来的思考
  2. acwing算法题--铁路与公路
  3. 一个SQL Server Sa密码破解的存储过程
  4. python搭建分布式集群_Spark完全分布式集群搭建【Spark2.4.4+Hadoop3.2.1】
  5. php mysql查询例子_php mysql一个查询优化的简单例子
  6. 基于springboot+vue的房屋租赁系统(前后端分离)
  7. 数据中心加湿系统计算及方法探讨【新规范加湿方式对比及计算分析】
  8. 叉乘点乘混合运算公式_职测解题技巧:数学运算的35个基础公式
  9. 解决工商银行网银插件报‘非正常运行的网银工具’问题
  10. 事务四大特征:原子性,一致性,隔离性和持久性(ACID)
  11. PS|你真的了解PS吗?
  12. 线程池的创建及参数设置详解
  13. python 矩阵类型转换_Python 矩阵转置的几种方法小结
  14. java 大文件上传 断点续传(Socket、IO流)
  15. React Native 拆分业务包 bundle拆包 分包 携程方案
  16. 兄弟连每集观后感,一些经典镜头的回顾
  17. 斯坦福cs224d(深度学习在自然语言处理上的应用)Lecture 2
  18. MAC的VMware Fusion使用U盘启动器启动系统
  19. 常用编码说明-ASCIIISO
  20. 用DIV+CSS制作四川成都美食网页介绍

热门文章

  1. ASP.Net页面刷新后自动滚动到原来位置
  2. Error applying BeanValidation relational constraints错误的解决
  3. SAP RFC user 最小权限
  4. 网页中的按钮无法显示问题解决
  5. 银行系统日终结算要多久_美股顽强翻红!两连跌终结,联储降息预期已超九成!制造业疲软消费者信心坚挺,三大股指又假摔?...
  6. Android 打开另一个APP,并传参
  7. table合并单元格宽度自适应
  8. data数值设置 vue_怎么改变vue中data的数据
  9. 从mysql 5.7 到 mysql 8.0
  10. Stack Overflow