浅谈C语言程序在Linux下的内存布局

浅谈C语言程序在Linux下的内存布局

​ 在了解内存布局前,先要了解程序的虚拟地址空间以及编译模式

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

​ 先了解CPU,然后再了解编译模式。再来看程序在内存中的分布。

一、CPU

​ CPU是计算机的核心,决定了计算机的数据处理能力和寻址能力。CPU一个时钟,也就是一次能处理的数据的大小由寄存器的位数和数据总线的宽度决定,通常所说的CPU的32位、64位可以理解为寄存器的位数,也可以理解为数据总线的宽度。

​ 以32位CPU为例子,即一次能处理32Bit,即4个字节的数据。典型的32位处理器是Intel 80386,它的数据总线宽度有32位,地址总线宽度也是32位,寻址能力为2^32 = 4GB

​ 数据总线决定了CPU单次的数据处理能力,主频决定了CPU单位时间内的数据处理次数,它们的乘积就是CPU单位时间内的数据处理量。

​ 数据总线用于在CPU和内存之间传输数据,地址总线用于在内存上定位数据,地址总线的宽度往往随着数据总线的宽度增大而增大,以访问更大的内存。

​ **同时CPU支持的物理内存只是理论上的数据,实际应用中会受到操作系统的限制,**比如说win7 64位家庭版最大支支持8GB和16GB的物理内存,win7 64位专业版可以支持到192GB的物理内存。但是32位CPU寻址能力没有这么大,所以要通过两次寻址来实现。

二、 编译模式

​ 为了兼容不同的平台,现代编译器都有32位和64位模式

在32位模式下:

​ 一个地址或者指针占用4个字节的内存,共有32位,理论上能够访问的虚拟内存空间大小位2^32=0X100000000 Bytes,即4GB虚拟地址空间,有效虚拟地址范围就是0xFFFFFFFF。也就是说不管实际物理内存有多大,程序能够访问的虚拟地址空间是4GB。程序能够使用的最大内存为4GB,跟物理空间没关系。

在64位模式下:

​ 一个指针或地址占用8个字节的内存,共有64位,理论上能够访问的虚拟内存空间大小为2^64。

​ 以现在的技术,物理内存尚且达不到这个数值,CPU都寻址能力也没有这么大,实现64为长的地址指挥增加系统的复杂度和地址转换的成本。

​ 所以,windows和Linux都会对虚拟地址进行了限制,仅使用虚拟地址的低48位(6个字节),总的虚拟空间大小位为2^48=256TB,而且任何虚拟地址的48位至63位必须与47位一致。

​ 如果内存大于物理内存,或者内存中剩余的空间不够容纳当前的程序,那么操作系统会将内存中用不到的一部分数据写入磁盘,等需要的时候再读取回来。程序只管使用4GB的内存,而不用关心硬件资源。

三、Linux下32位环境的用户空间内存分布

​ 了解了程序的内核空间和用户空间后,理论上一个32位程序可以拥有4GB的虚拟空间,程序要拿出一部分内存给操作系统内核使用,应用程序无法直接访问这一段内存。剩下的内存就分给自身的运行,也即是用户空间。


浅谈C语言程序在Linux下的内存布局_第1张图片

各个分区的作用:

浅谈C语言程序在Linux下的内存布局_第2张图片

  • 程序代码区用来保存指令,

  • 常量区、全局数据区、堆、栈都用来保存数据。

  • 常量区和全局数据区有时也被合称为静态数据区,意思是这段内存专门用来保存数据,在程序运行期间一直存在。

  • 程序代码区、常量区、全局数据区三个区在程序加载到内存后就分配好了,并且在程序运行期间一直存在,不能销毁也不能增加(大小已被固定),只能等到程序运行结束后由操作系统收回,所以全局变量、字符串常量等在程序的任何地方都能访问,因为它们的内存一直都在。

四、Linux下64位环境的用户空间内存分布情况

​ 在64位环境下,虚拟空间大小位256TB,Linux将高128TB空间分配给内核使用,将128TB的空间分配给用户程序使用。

浅谈C语言程序在Linux下的内存布局_第3张图片

​ 上面讲过,在64位环境下,虚拟地址只有最低48位有效。而且任何虚拟地址的48位至63位必须与47位数字一致。

​ 上图中,用户空间地址的47位是0,所以高16位也是0,换算成十六进制形式,最高的四个数都是0;内核空间地址的47位是1,所以高16位也是1,换算成十六进制形式,最高的四个数都是1。这样中间的一部分地址正好空出来,也就是图中的“未定义区域”,这部分内存无论如何也访问不到。

你可能感兴趣的:(C++,编程语言与内存,linux,编程语言)