所谓虚拟地址空间,就是程序可以使用的虚拟地址的有效范围。虚拟地址和物理地址的映射关系由操作系统决定,相应地,虚拟地址空间的大小也由操作系统决定,但还会受到编译模式的影响。

这节我们先讲解CPU,再讲解编译模式,让大家了解编译器是如何配合CPU来提高程序运行速度的。

CPU的数据处理能力

CPU是计算机的核心,决定了计算机的数据处理能力和寻址能力,也即决定了计算机的性能。CPU一次(一个时钟内)能处理的数据的大小由寄存器的位数和数据总线的宽度(也即有多少根数据总线)决定,我们通常所说的多少位的CPU,除了可以理解为寄存器的位数,也可以理解数据总线的宽度,通常情况下它们是相等的。

数据总线位于主板之上,不在CPU中,也不由CPU决定,严格来讲,这里应该说CPU能够支持的数据总线的最大根数,也即能够支持的最大数据处理能力,为了表达方便,本文才使用“CPU的数据总线”这一说法。

数据总线和主频都是CPU的重要指标:数据总线决定了CPU单次的数据处理能力,主频决定了CPU单位时间内的数据处理次数,它们的乘积就是CPU单位时间内的数据处理量。

我们常常听说,CPU主频在计算机的发展过程中飞速提升,从最初的几十 KHz,到后来的几百 MHz,再到现在的 4GHz,终于因为硅晶体的物理特性很难再提升,只能向多核方向发展。在这个过程中,CPU的数据总线宽度也在成倍增长,从早期的8位、16位,到后来的32位,现在我们计算机大部分都在使用64位CPU。

需要注意的是,数据总线和地址总线不是一回事,数据总线用于在CPU和内存之间传输数据,地址总线用于在内存上定位数据,它们之间没有必然的联系,宽度并不一定相等。实际情况是,地址总线的宽度往往随着数据总线的宽度而增长,以访问更大的内存。

1) 16位CPU

早期的CPU是16位的,一次能处理 16Bit(2个字节)的数据。这个时候计算机产业还处在早期,个人电脑也没有进入千家万户,也没有提出虚拟地址的概念,程序还是直接运行在物理内存上,操作系统对内存的管理非常简陋,程序员轻易就能编写一个恶意程序去修改其他程序的内存。

学过汇编的同学应该知道,典型的16位处理器是 Intel 8086,它的数据总线有16根,地址总线有20根,寻址能力为 2^20 = 1MB。

2) 32位CPU

随着计算机产业的进步,出现了32位的CPU,一次能处理 32Bit(4个字节)的数据。这个时候就提出了虚拟地址的概念,并被应用到CPU和操作系统中,由它们共同完成虚拟地址和物理地址的映射,这使得程序编写更加容易,运行更加安全。

典型的32位处理器是 Intel 的 80386 和 Intel Pentium 4(奔腾4):80386 的数据总线和地址总线宽度都是32位,寻址能力达4GB;Pentium 4的地址总线宽度是36位,理论寻址能力达64GB。

3) 64位CPU

现代计算机都使用64位的CPU,它们一次能处理64Bit(8个字节)的数据。典型的64位处理器是 Intel 的 Core i3、i5、i7 等,它们的地址总线宽度为 40~50 位左右。64位CPU的出现使个人电脑再次发生了质的飞跃。

实际支持的物理内存

CPU支持的物理内存只是理论上的数据,实际应用中还会受到操作系统的限制,例如,Win7  64位家庭版最大仅支持8GB或16GB的物理内存,Win7 64位专业版或企业版能够支持到192GB的物理内存。

Windows Server 2003 数据中心版专为大型企业或国家机构而设计,可以处理海量数据,分为32位版和64位版,32位版最高支持512GB的物理内存,这显然超出了32位CPU的寻址能力,可以通过两次寻址来实现。

编译模式

为了兼容不同的平台,现代编译器大都提供两种编译模式:32位模式和64位模式。

32位编译模式

在32位模式下,一个指针或地址占用4个字节的内存,共有32位,理论上能够访问的虚拟内存空间大小为 2^32 = 0X100000000 Bytes,即4GB,有效虚拟地址范围是 0 ~ 0XFFFFFFFF。 

也就是说,对于32位的编译模式,不管实际物理内存有多大,程序能够访问的有效虚拟地址空间的范围就是0 ~ 0XFFFFFFFF,也即虚拟地址空间的大小是 4GB。换句话说,程序能够使用的最大内存为 4GB,跟物理内存没有关系。

如果程序需要的内存大于物理内存,或者内存中剩余的空间不足以容纳当前程序,那么操作系统会将内存中暂时用不到的一部分数据写入到磁盘,等需要的时候再读取回来,这在《载入内存,让程序运行起来》中已经讲到。而我们的程序只管使用 4GB 的内存,不用关心硬件资源够不够。

如果物理内存大于 4GB,例如目前很多PC机都配备了8GB的内存,那么程序也无能为力,它只能够使用其中的 4GB。

64位编译模式

在64位编译模式下,一个指针或地址占用8个字节的内存,共有64位,理论上能够访问的虚拟内存空间大小为 2^64。这是一个很大的值,几乎是无限的,就目前的技术来讲,不但物理内存不可能达到这么大,CPU的寻址能力也没有这么大,实现64位长的虚拟地址只会增加系统的复杂度和地址转换的成本,带不来任何好处,所以 Windows 和 Linux 都对虚拟地址进行了限制,仅使用虚拟地址的低48位(6个字节),总的虚拟地址空间大小为 2^48 = 256TB。

需要注意的是:

  • 32位的操作系统只能运行32位的程序(也即以32位模式编译的程序),64位操作系统可以同时运行32位的程序(为了向前兼容,保留已有的大量的32位应用程序)和64位的程序(也即以64位模式编译的程序)。
  • 64位的CPU运行64位的程序才能发挥它的最大性能,运行32位的程序会白白浪费一部分资源。

目前计算机可以说已经进入了64位的时代,之所以还要提供32位编译模式,是为了兼容一些老的硬件平台和操作系统,或者某些场合下32位的环境已经足够,使用64位环境会增大成本,例如嵌入式系统、单片机、工控等。

这里所说的32位环境是指:32位的CPU + 32位的操作系统 + 32位的程序。

另外需要说明的是,32位环境拥有非常经典的设计,易于理解,适合教学,现有的很多资料都是以32位环境为基础进行讲解的。本教程也是如此,除非特别指明,否则都是针对32位环境。相比于32位环境,64位环境的设计思路并没有发生质的变化,理解了32环境很容易向64位环境迁移。

C语言:虚拟地址 和编译模式的更多相关文章

  1. 关于HotSpot VM以及Java语言的动态编译 你可能想知道这些

    目录 1 HotSpot VM的历史 2 HotSpot VM 概述 2.1 编译器 2.2 解释器 2.3 解释型语言 VS 编译型语言 3 动态编译 3.1 什么是动态编译 3.2 HotSpot ...

  2. Atitit.dart语言的特性  编译时js语言大总结

    Atitit.dart语言的特性  编译时js语言大总结 1. 原型环境1 1.1. Dart可以编译js3 2. 第二个期待的理由是Dart的语言特性,没有什么特别特性好像,类似java c#一小时 ...

  3. Release编译模式下,事件是否会引起内存泄漏问题初步研究

    题记:不常发生的事件内存泄漏现象 想必有些朋友也常常使用事件,但是很少解除事件挂钩,程序也没有听说过内存泄漏之类的问题.幸运的是,在某些情况下,的确不会出问题,很多年前做的项目就跑得好好的,包括我也是 ...

  4. 用java语言实现事件委托模式

    http://blog.csdn.net/yanshujun/article/details/6494447 用java语言实现事件委托模式 2010-04-27 00:04 2206人阅读 评论(1 ...

  5. 微信小程序 - 开发工具之编译模式

    在开发中,遇到一个层级较深的页面,每次都要点击好多步才能调试,也比较闹心,有了自定义编译模式,就方便很多了 点击红圈处, 选择 "+添加编译模式" , 默认的, 启动页面会填入当前 ...

  6. “标准查询运算符”是组成语言集成查询 (LINQ) 模式的方法

    “标准查询运算符”是组成语言集成查询 (LINQ) 模式的方法.大多数这些方法都在序列上运行,其中的序列是一个对象,其类型实现了IEnumerable<T> 接口或 IQueryable& ...

  7. angular2的编译模式之AOT和JIT

    原文 https://www.jianshu.com/p/c959d90e91ce 大纲 1.angular应用为什么需要编译 2.angular的编译模式类型 3.JIT(Just-In-Time) ...

  8. xmake从入门到精通8:切换编译模式

    xmake是一个基于Lua的轻量级现代化c/c++的项目构建工具,主要特点是:语法简单易上手,提供更加可读的项目维护,实现跨平台行为一致的构建体验. 本文我们会详细介绍下如何在项目构建过程中切换deb ...

  9. C语言程序经过编译链接后形成二进制映像文件的组成

    C语言程序经过编译链接后形成二进制映像文件由栈,堆,数据段,代码段组成,其中数据段又分为:只读数据段,已经初始化读写数据段,未初始化数据段(BSS段).如下图所示: 1.栈区(stack):由编译器自 ...

随机推荐

  1. 白*衡(Color Constancy,无监督AWB):CVPR2019论文解析

    白*衡(Color Constancy,无监督AWB):CVPR2019论文解析 Quasi-Unsupervised Color Constancy 论文链接: http://openaccess. ...

  2. halcon——缺陷检测常用方法总结(光度立体)

    引言 机器视觉中缺陷检测分为一下几种: blob+特征(官方示例surface_scratch.hdev) blob+差分+特征(官方示例pcb_inspection.hdev) 光度立体 特征训练 ...

  3. String类对象相加时做了什么

    我们都知道java中的加号操作符除了加法.表示正数之外,还可以用作字符串的连接.初学java时,你很可能会碰到类似下面的题目: 以下这段代码产生了几个String对象: String str1 = & ...

  4. 【SQLite】SQLite文件突然变大怎么办?瘦身办法

    使用VACUUM命令即可: VACUUM 命令通过复制主数据库中的内容到一个临时数据库文件,然后清空主数据库,并从副本中重新载入原始的数据库文件.这消除了空闲页,把表中的数据排列为连续的,另外会清理数 ...

  5. Spring Boot 实战:如何自定义 Servlet Filter

    1.前言 有些时候我们需要在 Spring Boot Servlet Web 应用中声明一些自定义的 Servlet Filter来处理一些逻辑.比如简单的权限系统.请求头过滤.防止 XSS 攻击等. ...

  6. java并发编程JUC第十二篇:AtomicInteger原子整型

    AtomicInteger 类底层存储一个int值,并提供方法对该int值进行原子操作.AtomicInteger 作为java.util.concurrent.atomic包的一部分,从Java 1 ...

  7. 解析 Nebula Graph 子图设计及实践

    本文首发于 Nebula Graph 公众号 NebulaGraphCommunity,Follow 看大厂图数据库技术实践. 前言 在先前的 Query Engine 源码解析中,我们介绍了 2.0 ...

  8. 『无为则无心』Python基础 — 11、Python中的数据类型转换

    目录 1.为什么要进行数据类型转换 2.数据类型转换本质 3.数据类型转换用到的函数 4.常用数据类型转换的函数 (1)int()函数 (2)float()函数 (3)str()函数 (4)bool( ...

  9. 地图可视化神器keplergl新增对jupyter lab 3.0的支持

    就在几天前,地图可视化神器kepler.gl面向Python的接口库keplergl迎来了新的0.3.0版本更新. 虽然官方文档还并未及时更新相关的内容说明,但我在快速地试用之后发现,现在的keple ...

  10. 14.4、web排错三部曲

    1.在客户端上ping服务器端ip : ping 服务器ip地址 :#排除线路问题: 2.在客户端上telnet服务器端Ip 端口号: telnet 服务器ip地址 端口号:#排除防火墙的影响: 3. ...