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

这节我们先讲解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. es api

    GET content-split-*/_search { "query": { "bool" : { "must" : [ { " ...

  2. python 获取当天和前几天时间数据

    python 获取当天和前几天时间数据 import datetime from datetime import datetime, date, timedelta def dayDateRange( ...

  3. Keil MDK5 安装教程(附安装包百度云)

    关注微信公众号"龙行单片机",后台回复"安装包"获取最新安装包百度云链接. 1.MDK5.11a 安装 双击 mdk511a.exe,进行安装.这里我们将其安装 ...

  4. 深度学习加速器堆栈Deep Learning Accelerator Stack

    深度学习加速器堆栈Deep Learning Accelerator Stack 通用张量加速器(VTA)是一种开放的.通用的.可定制的深度学习加速器,具有完整的基于TVM的编译器堆栈.设计了VTA来 ...

  5. 容斥+dp (一)

    ARC115 E AtCoder Problem Statement Given is a sequence of \(N\) integers \(A_1\),\(A_2\),...,\(A_N\) ...

  6. Java如何利用for循环在控制台输出正方形对角线图形

    1 /* 2 利用循环在控制台输出如下正方形对角线图形 3 * * * * * * * * * * * 4 * * * * 5 * * * * 6 * * * * 7 * * * * 8 * * * ...

  7. 性能工具之Jmeter小白入门系列之一

    一.简单了解 Apache JMeter The Apache JMeter application is open source software, a 100% pure Java applica ...

  8. 【NX二次开发】切换模块的方法,切换到制图模块

    源码(NX12.0): Session theSession = NXOpen::Session::GetSession(); theSession->ApplicationSwitchImme ...

  9. Luatools v2烧录教程(适用于2G、4G Cat.1、4G Cat.4模块)

    目录,可以根据需要直接点击跳转: 下载LuaTools工具 2G模块烧写教程(Air2xx系列.Air8xx系列) 连接模块 刷入AT版本的lod 刷入任意的lod固件 下载lua脚本文件 [4G 模 ...

  10. Linux中测试网络命令

    ping IP -t 是持续性查看网络状态