引言
在我们接触Linux系统的过程中,了解程序中不同的变量在内存里面的分布情况,才能更加深入去知道变量的特征。并且,在整个编写程序的过程中,其实也是对内存的一种操作方法。
程序运行的内存布局
首先使用file
命令查看程序文件的格式等基本信息:
但是我们如果要查看文件的内部信息,如果使用vi
命令是看不懂的,因为这是一个二进制文件。
使用 readelf 文件名 -S
命令专门查看二进制文件:
从上图中可以看到一个可执行文件被分为了30段
其中有一些是加载程序时,系统需要使用的(这个暂不关心)
值得我们关心的是我上图框起来的几个段:
.init
: 代码段,init是操作系统自动添加的,用于启动代码(main函数),组织外部参数,环境变量等功能,基本每个程序都拥有。.text
:代码段,用于存放main函数,自定义函数等所有程序代码。.rodata
:用于存放只读数据,例如:常量。.data
:用于存放已初始化静态数据,例如:全局变量与局部变量。.bss
:用于存放未初始化的静态数据。
内存布局图解
1.当程序运行时./main
,硬盘中的程序与内存的变化:
将硬盘中程序的信息(代码,数据)复制到内存,内存运行。
从上图中也可以看到程序中的段从硬盘通过拷贝的方式出现在内存中。
而内存的地址是:[0x8048000,0xC0000000]我们也可以通过打印地址的区间,来确定每个区间的段位置。
2.程序运行时,内存中的栈与堆:
纠错:是malloc、calloc、realloc函数分配内存
- 使用虚线表示程序在运行中,栈与堆在内存中是可以弹性变化的,而实线则表示程序运行中不变的。
- 栈主要存放程序运行中的局部变量(形参)。
- 栈的大小一般为2-4M,因此编程时要杜绝一些巨大变量放入栈中。
- 堆主要是存放用户使用了mallo、callo、readlo等函数分配的内存。
浅谈为什么静态数据要分为.bss与data存放
从上文可以知道:
BSS段主要存放未初始化的静态数据。
DATA段主要存放已初始化的静态数据。
在C语言中,任何静态数据如果没有进行初始化,那么系统会自动将其初始化为0。
举个例子:
有一个数组:int a[1000]
,并没有进行初始化
那么,在程序运行时,a数组中1000个元素都会被初始化为0。
如果按照一般的思维,在编译的过程中,这1000个元素将会被初始化为0存放在硬盘中,然后运行时,将1000个为0的元素拷贝到内存中。
可见,这样是不可取的!系统不会允许你做那么笨的事~
因此,程序块中会将这1000个未初始化的元素都存放在BSS段中,并且在运行时,拷贝到内存后,再对这1000个元素初始化为0。这样的做法大大节省了硬盘的空间。
那么如果这个数组是:int a[1000]={1,2,.....1000};
已经被初始化。
那么,就不能按照上面的思维了。如果,继续将这个数组存放在BSS段,内存不知道要给它赋以什么样的值。
因为,数组已经初始化,不得不在硬盘中分配空间加以存放,因此就会存放在DATA段中,然后程序运行时,只能一个个拷贝过去。