C语言:虚拟地址 和编译模式
所谓虚拟地址空间,就是程序可以使用的虚拟地址的有效范围。虚拟地址和物理地址的映射关系由操作系统决定,相应地,虚拟地址空间的大小也由操作系统决定,但还会受到编译模式的影响。
这节我们先讲解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语言:虚拟地址 和编译模式的更多相关文章
- 关于HotSpot VM以及Java语言的动态编译 你可能想知道这些
目录 1 HotSpot VM的历史 2 HotSpot VM 概述 2.1 编译器 2.2 解释器 2.3 解释型语言 VS 编译型语言 3 动态编译 3.1 什么是动态编译 3.2 HotSpot ...
- Atitit.dart语言的特性 编译时js语言大总结
Atitit.dart语言的特性 编译时js语言大总结 1. 原型环境1 1.1. Dart可以编译js3 2. 第二个期待的理由是Dart的语言特性,没有什么特别特性好像,类似java c#一小时 ...
- Release编译模式下,事件是否会引起内存泄漏问题初步研究
题记:不常发生的事件内存泄漏现象 想必有些朋友也常常使用事件,但是很少解除事件挂钩,程序也没有听说过内存泄漏之类的问题.幸运的是,在某些情况下,的确不会出问题,很多年前做的项目就跑得好好的,包括我也是 ...
- 用java语言实现事件委托模式
http://blog.csdn.net/yanshujun/article/details/6494447 用java语言实现事件委托模式 2010-04-27 00:04 2206人阅读 评论(1 ...
- 微信小程序 - 开发工具之编译模式
在开发中,遇到一个层级较深的页面,每次都要点击好多步才能调试,也比较闹心,有了自定义编译模式,就方便很多了 点击红圈处, 选择 "+添加编译模式" , 默认的, 启动页面会填入当前 ...
- “标准查询运算符”是组成语言集成查询 (LINQ) 模式的方法
“标准查询运算符”是组成语言集成查询 (LINQ) 模式的方法.大多数这些方法都在序列上运行,其中的序列是一个对象,其类型实现了IEnumerable<T> 接口或 IQueryable& ...
- angular2的编译模式之AOT和JIT
原文 https://www.jianshu.com/p/c959d90e91ce 大纲 1.angular应用为什么需要编译 2.angular的编译模式类型 3.JIT(Just-In-Time) ...
- xmake从入门到精通8:切换编译模式
xmake是一个基于Lua的轻量级现代化c/c++的项目构建工具,主要特点是:语法简单易上手,提供更加可读的项目维护,实现跨平台行为一致的构建体验. 本文我们会详细介绍下如何在项目构建过程中切换deb ...
- C语言程序经过编译链接后形成二进制映像文件的组成
C语言程序经过编译链接后形成二进制映像文件由栈,堆,数据段,代码段组成,其中数据段又分为:只读数据段,已经初始化读写数据段,未初始化数据段(BSS段).如下图所示: 1.栈区(stack):由编译器自 ...
随机推荐
- OpenResty搭建高性能服务端
OpenResty搭建高性能服务端 Socket编程 Linux Socket编程领域为了处理大量连接请求场景,需要使用非阻塞I/O和复用,select.poll.epoll是Linux API提 ...
- GO语言复合类型02---数组
package main import "fmt" /* 固定长度.固定类型的数据容器 */ /*数组的声明*/ func main031() { //var array [5]i ...
- (转)修改python默认排序方式
在Java中,自定义类可以通过继承comparable接口,重写compareTo方法来使用内置sort()函数来对自定义对象排序,我就在想Python中有没有类似的操作. 首先随便写个自定义类,比如 ...
- camera数字降噪(DNR)
camera数字降噪(DNR) 闭路电视摄像机 无论多么出色和弱光,在黑暗中拍摄视频监控录像时都会不可避免地产生一些噪音.噪声是任何电子通信中不可避免的部分,无论是视频还是音频.本质上是静态的–视频信 ...
- 多尺度目标检测 Multiscale Object Detection
多尺度目标检测 Multiscale Object Detection 我们在输入图像的每个像素上生成多个锚框.这些定位框用于对输入图像的不同区域进行采样.但是,如果锚定框是以图像的每个像素为中心生成 ...
- PyQt5开发实践(一、准备篇)
前言 近一年来我开发了不少PyQt小项目,因为之前没用过使用C++语言的Qt,所以可以算是从零基础开始边学边做的,这个过程中再一次体会到国内技术社区的匮乏-- 国内关于PyQt的资料说少不少,说多也不 ...
- Java课程设计-算术运算测试(D级) 齐鲁工业大学 计科20-1 王瀚垠 202003010033
Java课程设计-算术运算测试(D级) 齐鲁工业大学 计科20-1 王瀚垠 202003010033 目录 1.项目简介 2.项目采用技术 3.功能需求分析 4.项目亮点 5.项目功能架构图和UML类 ...
- C# 扫描并读取图片中的文字
本文介绍如何通过C# 程序来扫描并读取图片中的文字,这里以创建一个.Net Core程序为例.下面是具体步骤,供参考. 程序测试环境: Visual Studio版本要求不低于2017 图片扫描工具: ...
- MySQL的自增ID用完了,怎么办?
既然这块知识点不清楚,那回头就自己动手实践下. 首先,创建一个最简单的表,只包含一个自增id,并插入一条数据. create table t0(id int unsigned auto_increme ...
- Kafka 的这些原理你懂吗
如果只是为了开发 Kafka 应用程序,或者只是在生产环境使用 Kafka,那么了解 Kafka 的内部工作原理不是必须的.不过,了解 Kafka 的内部工作原理有助于理解 Kafka 的行为,也利用 ...