学习Windows程序设计也有一些时间了,为了记录自己的学习成果,以便以后查看,我希望自己能够坚持写下一系列的学习心得,对自己学习的内容进行总结,同时与大家交流。因为刚学习所以可能有的地方写不不正确,希望大家能够指出。

在学习了一定的Windows API后我决定进入到一些基础的学习,希望能够学习一些原理性的知识,能够做到知其然的同时知其所以然。为了达到这个目的,这段时间我学习了一些计算机的基础知识,在这写下这篇博客,总结一下。

在早期的16位8086CPU中我们使用段与段内的偏移偏移的方式寻址,得到的是真实的物理地址,当时的寄存器是16位而地址总线是20位,为了充分利用这些地址总线,Intel的工程师采用的是分段的方式,将段寄存器与通用寄存器中的数值通过地址加法器合成20位的地址,具体的合成方式为段地址 * 16 + 偏移地址,利用这种方式得到的都是真实的物理地址。8086系列的CPU之所以成为一个划时代的产物就是因为这种分段的思想,而这种思想一直沿用至今。但是8因为086CPU得到的都是真实的物理地址,所以在早期的程序设计中不得不详细考虑内存段的划分,有可能出现后一个程序将前一个程序的内存占用,这种方式非常不安全。

到32位CPU的诞生产生了一种新的寻址方式,80386CPU有32位地址总线,寻址区间为2的32次方为4GB。所以用32位的通用寄存器都可以访问4GB的内存空间,这个时候段寄存器不在存储段的首地址段,寄存器DS、CS、ES等寄存器中存储的是段选择子的索引。段选择子的概念出现在32位CPU中的保护模式中,在保护模式下,每个内存段都有一个64位的结构体用来描述这段内存的基本信息叫做段描述符,段描述符包括安全级别,段的基地址等信息,系统将所有内存段的64位描述符存储在一个段描述符表中,将段寄存器中的16位数据作为段描述符表的索引,称为选择子。为了管理段描述符表,80386引入两个寄存器一个是48位的GDTR(全局段描述符表寄存器)另一个是16位的LDTR(局部段描述符表寄存器)分别指向GDT(全局段描述符表)和LDT(局部段描述符表)。

GDT(Global Descriptor Table)包含系统中所有任务都可用的段描述符,通常包含描述操作系统所使用的代码段、数据段和堆栈段的描述符及各任务的LDT段等;全局描述符表只有一个。而LDTR(Local Descriptor Table)80386处理器设计成每个任务都有一个独立的LDT。它包含有每个任务私有的代码段、数据段和堆栈段的描述符,也包含该任务所使用的一些门描述符,如任务门和调用门描述符等。系统根据不同的任务切换不同的LDT。这样便于实现不同进程间内存的隔离。

为了确定所在段描述符的位置,段寄存器中的16位数据中只有13位表示段描述中的索引。第0位、第1位合起来表示程序的等级,第2位TI位用来表示在段描述符的位置;TI=0表示在GDT中,TI=1表示在LDT中。对于一个虚拟地址XXXX:YYYYYYYY首先判断XXXX中TI位的值,当TI = 0时表示的是全局段描述符表,这个时候首先利用GDTR中的值确定GDT的位置,然后直接取段寄存器中高13位的值作为索引在GDTR中查找得到相应的段描述符,由于段描述符包含段的基址、限长、优先级等各种属性,这就得到了段的起始地址;当TI等于1时表示的是局部的段描述符表,这个时候寻址变得相对比较复杂,第一步还是从GDTR获得GDT的位置,然后根据LDTR中的16位数值作为索引在GDT中查找LDT所在位置,然后才是根据XXXX中的高13位作为索引在LDT中查找得到相应的段描述符,由于段描述符包含段的基址、限长、优先级等各种属性,这就得到了段的起始地址。

这两种方式的步骤如下图:

在这里我们只是说得到线性地址并没有说得到内存地址,那么线性地址是否就是内存地址呢?可以是也可以不是,这取决于80386的分页机制是否被使用。

在早期的分段模式下,系统回收程序使用的内存可能会残留很小的内存碎片,导致任何程序都不能使用,为了解决这一问题,80386CPU提供了一种分页机制,系统将固定大小的内存块分为一页,在一页中在使用段分配的方式,每页的大小有系统决定,Windows系统的页大小为4KB。每页物理内存可以根据“页目录”和“页表”,随意映射到不同的线性地址上。这样,就可以将物理地址不连续的内存的映射连到一起,在线性地址上视为连续。而是否启用内存分页机制是由80386处理器新增的CR0寄存器中的位31(PG位)决定的。如果PG=0,则分页机制不启用,这时所有指令寻址的地址(线性地址)就是系统中实际的物理地址;当PG=1的时候,80386处理器进入内存分页管理模式,所有的线性地址要经过页表的映射才得到最后的物理地址。当每页大小为4KB时,我们得到的32位线性地址中高20位表示页号,低12位表示页中的偏移地址,这样通过页映射的方式我们可以将线性地址转化成对应的物理地址。

到这里我们可引出几个重要的概念:

1)32位机器中共有2中段描述符表,每个表中有2^13个表项,每个表项代表一个段首地址,而每一段的段内偏移最大为2^32B所以32位机器的理论寻址范围为2^13 * 2^1 * 2^32 = 2^(13 + 1 + 32) = 64TB;

2)系统为每个应用程序分配4GB的虚拟内存,并且由于保护模式的相关机制,这4GB的内存为每个应用程序独享

3)由于保护模式不同应用程序中相同的逻辑地址最终映射到不同的内存地址,所以在应用程序中我们不必过多操心程序所使用的内存被其他应用程序占用。

在Windows的保护模式中,将应用程序分级分为RING0到RING3,其中RING0的级别最高、GING3的级别最低,虽说分为4个级别但是实际上只使用了两个,Windows为了与其他CPU兼容,只使用2个,RING0主要是内核代码、RING3主要是用户代码,那是不是说RING3级别的代码就不能访问RING0级别的内存呢?这个自然也不是,Windows我们都知道Windows提供了一系列的API
,其中我们可以调用相应的API访问内核所在的内存,只是不能直接访问内核代码,也就是说不能直接用jmp指令访问内核代码,但是可以使用call指令调用,API对于程序员来说是不透明的。

Windows保护模式下主要机制有:

1)Windows提供不同安全级别,不同安全级别的代码访问内存的权限也不一样

2)不同进程的内存都是独立的,每个进程独享自己的4GB内存,不同进程即使在代码中使用相同的虚拟地址,系统也会映射到不同 的地址空间

Windows程序设计学习笔记(一)Windows内存管理初步的更多相关文章

  1. iOS学习笔记之ARC内存管理

    iOS学习笔记之ARC内存管理 写在前面 ARC(Automatic Reference Counting),自动引用计数,是iOS中采用的一种内存管理方式. 指针变量与对象所有权 指针变量暗含了对其 ...

  2. Windows程序设计学习笔记(1):一个简单的windows程序

    <Windows程序设计>(第五版)(美Charles Petzold著) #include<windows.h> LRESULT CALLBACK WndProc(HWND, ...

  3. 【cocos2d-x 3.x 学习笔记】对象内存管理

    内存管理 内存管理一直是一个不易处理的问题.开发人员必须考虑分配回收的方式和时机,针对堆和栈做不同的优化处理,等等.内存管理的核心是动态分配的对象必须保证在使用完成后有效地释放内存,即管理对象的生命周 ...

  4. JVM学习笔记一:内存管理

    参考资料 本文参考:<深入理解Java虚拟机>作者 周志明 知识产权归作者所有 走近java java组成部分:java语言.各平台虚拟机.Class文件结构.java api 类库.第三 ...

  5. Windows程序设计学习笔记(五)——菜单资源和加速键的使用

    菜单可能是Windows提供的统一用户界面中最重要的一种方式,菜单通常在标题栏的下一行显示,这一栏叫做菜单栏,菜单栏中的每一项称之为菜单项,菜单栏中的每一个菜单项在激活时会显现一个下拉菜单(也可以说是 ...

  6. Windows程序设计学习笔记(四)自绘控件与贴图的实现

    Windows系统提供大量的控件供我们使用,但是系统提供的控件样式都是统一的,不管什么东西看久了自然会厌烦,为了使界面更加美观,添加一些新的东西我们需要自己绘制控件. 控件在默认情况下并不进行自绘,如 ...

  7. windows程序设计学习笔记(一)

    windows里的变量类型 1.简单重定义windows变量 BOOL (TRUE FALSE) INT UINT(32位,4字节) LONG DWORD(32位,4字节) lParam,wParam ...

  8. 20145213《Java程序设计学习笔记》第六周学习总结

    20145213<Java程序设计学习笔记>第六周学习总结 说在前面的话 上篇博客中娄老师指出我因为数据结构基础薄弱,才导致对第九章内容浅尝遏止地认知.在这里我还要自我批评一下,其实我事后 ...

  9. python学习笔记--Django入门四 管理站点--二

    接上一节  python学习笔记--Django入门四 管理站点 设置字段可选 编辑Book模块在email字段上加上blank=True,指定email字段为可选,代码如下: class Autho ...

随机推荐

  1. Scheme -- Hierarchical Structures

    Question: produce a deep-reverse procedure that takes a list as argument  and returns as its value t ...

  2. 【Notification】屏蔽特定应用的通知提示

    须要默认屏蔽特定app的通知提示 设置app是否接收通知的界面 点击每一个条目进去的界面 AppNotificationSettings extends SettingsPreferenceFragm ...

  3. 解决 PclZip 中文乱码问题

        在使用 Pclzip 时出现无法压缩/解压文件的现象,追踪错误信息发现无法打开文件/文件夹.可是文件夹权限正确,打印文件路径之后发现是乱码. 出现这个问题的解决办法是windows下zip内的 ...

  4. 前端(各种demo)三:优惠券,热区,等模块的实现(css方式)

    各种样式的css实现 1.优惠券样式的实现: 2.热区的实现:   在电商平台上总会发出各种券,需要对应到不同的产品,对应到不同的服务.而使用券可以使用UED的设计稿里的照片,但是本来一次性的加载过多 ...

  5. 在java项目中加入百度富文本编辑器

    富文本编辑器在项目中很常见,他可以将文本,图片等信息存入数据库,在编辑一些图文混排的信息的时候很有用,比如商城项目的商品详情页,包含很多带有样式的文字和图片. 此前一直使用的百度的富文本编辑器uedi ...

  6. Zabbix安装之路

    这次的教程多半是搬运过来的,但都经过小轩亲自测试与修改了.文章最后将公布原资源地址.此篇算是整合,但又不全是整合. 依旧需求开篇:上头让小轩监控一下服务器的情况,在前几篇也有所提到.于是小轩就到处去找 ...

  7. centos6.5安装git

    1.git源码地址:http://codemonkey.org.uk/projects/git-snapshots/git/

  8. Java实现的电脑已连接WiFi热点的导入导出小工具

    很多时候我们电脑连接了很多无线WiFi,只要连接过一次,电脑就会记下该热点的密码,方便我们下一次连接.但是问题来了,一旦我们重装系统,之前连接过的WiFi就丢失了,想要连接就得再输入密码,为了 解决这 ...

  9. 通过自动回复机器人学Mybatis 笔记:接口式编程

    [接口式编程]尚未遇见Spring --> 代码量反而增加 1.增加约定,减少犯错的可能(不用直接去写字符串 修改点1:命名空间 修改点2:增加接口,方法名与配置文件中的id对应 package ...

  10. Cookie的简单用法

    ASP.NET初学者使用cookie的时候会感觉很陌生,在学习的过程中掌握cookie对象的增删改查非常有必要,,下面是我学习的时候经常用到的这些方法 写入和读取Cookie都需要用户Respone对 ...