windows和linux的内存管理

      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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/435010.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python垃圾邮件识别_【Python】垃圾邮件识别

下载W3Cschool手机App,0基础随时随地学编程导语利用简单的机器学习算法实现垃圾邮件识别。让我们愉快地开始吧~相关文件密码: qa49数据集源于网络,侵歉删。开发工具Python版本:3.6.4相关模块:scikit-learn模块;jieba模…

修改Linux内核的启动Logo和禁用启动光标

Linux内核下使用的图片文件类型是pnm和PPm格式的,所以在开始介绍修改linux内核启动LOGO之前, 1,先需要介绍一下怎么样设计自己开始logo的ppm图片,首先选择一张png格式的图片 使用如下命令确保你必须安装以下的工具(pngtopnm,pnmqu…

JavaScript 判断浏览器类型

var Sys {}; var ua navigator.userAgent.toLowerCase(); var s; (s ua.match(/msie ([\d.])/)) ? Sys.ie s[1] : (s ua.match(/firefox\/([\d.])/)) ? Sys.firefox s[1] : (s ua.match(/chrome\/([\d.])/)) ? Sys.chrome s[1] : (s ua.match(/opera.(…

python time perf_Python Time 的学习笔记

PyNotes-timePyNotes(2)关于time的简单介绍参考资料概述time模块 时间戳的获取、时间格式的转换和程序运行时间的计算。方法时间的获取time.time()以floa浮点数获取当前时间戳,即计算机内部时间值,epoch 是1970年1月1日00:00:00(UTC)>>> time.t…

Linux logo和屏幕光标

logo和屏幕光标 Linux默认开机LOGO一般都是80x80的小企鹅图标,有时候为了一些效果,希望在Linux 启动过程中,全屏看到用户自定义的LOGO,这就需要为Linux增加新的LOGO。 准备png图片 使用任何图片软件,制作一张自定义…

arcgis选出点规定范围的面

示例数据如下 对点数据进行缓冲区建立 打开缓冲区工具箱 主要设置输入数据和距离(缓冲范围) 缓冲结果如下 接下来进行空间连接 输入目标要素(选出的面)和连接要素(缓冲的结果) 打开空间连接的属性表 选中我…

函数实现-aoti-atol

1. 函数原型 int atoi ( const char * str ); long int atol ( const char * str ); 2. 函数工作 atoi是将字符串转化为整型,atol是将字符串转化为长整型,这两个函数的实现十分相似。工作步骤基本如下: 跳过若干空格、制表符等 如果有…

python2卸载后yum不可用_centos7误删除python2导致的python和yum不可用处理-阿里云开发者社区...

centos7查看版本cat /etc/redhat-release // 我这边是 CentOS Linux release 7.6.1810 (Core)强制删除已安装程序及其关联rpm -qa|grep python|xargs rpm -ev --allmatches --nodeps删除所有残余文件 ##xargs,允许你对输出执行其他某些命令whereis python |xargs rm -frv验证删…

arcgis批量按掩膜提取栅格

新建工具箱 迭代要素类 插入栅格

SIP协议学习1

SIP协议是由IETF提出的在IP网络上进行多媒体通信的应用层控制协议。采用分层的方法来创建服务,是应用层上的一个控制协议,用来创建,修改和终止有多个参与者的多媒体会话进程。参与会话的成员可以通过组播,单播或者两者结合的方式进…

一些关于罗马字符的知识

I 1 V 5 X 10 L 50 C 100 D 500 M 1000 下面是关于构造罗马数字的一些通用的规则的介绍: 字符是叠加的。I 表示 1,II 表示 2,而 III 表示 3。VI 表示 6 (字面上为逐字符相加,“5 加 1”),VII 表示 7&#xff0c…

python 分词 识别_python分词如何实现新词识别

2013-12-19 回答# -*- coding: utf-8 -*-import jiebacreated on 2015-11-23def word_split(text):"""split a text in words. returns a list of tuple that contains(word, location) location is the starting byte position of the word."""…

Oracle数据库游标操作

1、含有参数的游标 declare cursor cur_my (mv number) is select * from Person where no<mv;begin for tem in cur_my(4) loop DBMS_OUTPUT.put_line(name:||tem.name); end loop;end; 2、设置引用游标declare temp_row Person%rowtype; type my_type is ref curs…

SIP协议学习2-pjsip

一、 在windows下利用vc6.0编译pjsip源码 首先阅读文档readme.txt&#xff0c;查找在win32平台源码的编译方法。自己总结方法如下&#xff1a; a.设置pjsua为当前活动工程 b.因为编译的时候提醒缺少config_site.h文件&#xff0c;所以在pjlib/include/pj/下新建一个空的c…

python库快速安装_python的pip快速安装代码

pip install xx,经常由于网速&#xff0c;或者安装版本问题导致安装速度慢超时等问题&#xff0c;现提供一个py镜像安装代码&#xff0c;安装库文件前执行下这个程序&#xff0c;可以很快下载cmd 进入命令提示符python .py文件位置pip install xx 安装库的名称import osini&quo…

基于C#的AE+IDL二次桌面端程序开发

目录 一、内容 1.2 实训内容 1.2.1 IDL综合开发 1.2.2 基于AO/AE的GIS二次开发 1.2.3 COM_IDL_connect组件开发 三、 实训软硬件环境 四、实训内容及成果 4.1 平台总体描述 4.1.1 系统简介 4.1.2 系统功能 4.2 基础模块 4.2.1…

PJSIP学习笔记——从simple_pjsua.c示例程序了解PJSUA-LIB的基本使用流程

要了解pjsip的使用&#xff0c;simple_pjsua.c是一个很好的例子&#xff0c;虽然代码只有短短的172行&#xff0c;却展示了pjsua-lib层的完整使用流程、注册流程和基本呼叫流程。 下面是学习过程中整理的simple_pjsua.c中的main函数主要流程&#xff1a; 先来看看pjsip-apps/s…

arcgis字段计算器--随机数

代码 def a():number arcgis.rand(Integer 0 25)return number 结果