深入理解C语言内存管理
之前在学Java的时候对于Java虚拟机中的内存分布有一定的了解,但是最近在看一些C,发现居然自己对于C语言的内存分配了解的太少。
问题不能拖,我这就来学习一下吧,争取一次搞定。?在任何程序设计环境及语言中,内存管理都十分重要。
内存管理的基本概念
分析C语言内存的分布先从Linux下可执行的C程序入手。现在有一个简单的C源程序hello.c
1 #include
2 #include
3 int var1 = 1;
4
5 int main(void) {
6 int var2 = 2;
7 printf("hello, world!\n");
8 exit(0);
9 }
经过gcc hello.c进行编译之后得到了名为a.out的可执行文件
[tuhooo@localhost leet_code]$?ls -al a.out-rwxrwxr-x. 1 tuhooo tuhooo 8592 Jul 22 20:40 a.out
ls命令是查看文件的元数据信息
[tuhooo@localhost leet_code]$?file a.outa.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=23c58f2cad39d8b15b91f0cc8129055833372afe, not stripped
file命令用来识别文件类型,也可用来辨别一些文件的编码格式。
它是通过查看文件的头部信息来获取文件类型,而不是像Windows通过扩展名来确定文件类型的。
[tuhooo@localhost leet_code]$?size a.out
text?
data
bss
dec
hex
filename
(代码区静态数据)
(全局初始化静态数据)
(未初始化数据区)?
(十进制总和)
(十六制总和)
(文件名)
1301
560
8
1869
74d
a.out
显示一个目标文件或者链接库文件中的目标文件的各个段的大小,当没有输入文件名时,默认为a.out。
size:支持的目标: elf32-i386 a.out-i386-linux efi-app-ia32 elf32-little elf32-big srec symbolsrec tekhex binary ihex trad-core。
那啥,可执行文件在存储(也就是还没有载入到内存中)的时候,分为:代码区、数据区和未初始化数据区3个部分。
进一步解读
(1)代码区(text segment)。存放CPU执行的机器指令(machine instructions)。通常,代码区是可共享的(即另外的执行程序可以调用它),因为对于频繁被执行的程序,只需要在内存中有一份代码即可。代码区通常是只读的,使其只读的原因是防止程序意外地修改了它的指令。另外,代码区还规划了局部变量的相关信息。
(2)全局初始化数据区/静态数据区(initialized data segment/data segment)。该区包含了在程序中明确被初始化的全局变量、静态变量(包括全局静态变量和局部静态变量)和常量数据(如字符串常量)。例如,一个不在任何函数内的声明(全局数据):
1 int maxcount = 99;
使得变量maxcount根据其初始值被存储到初始化数据区中。
1 static mincount = 100;?
这声明了一个静态数据,如果是在任何函数体外声明,则表示其为一个全局静态变量,如果在函数体内(局部),则表示其为一个局部静态变量。另外,如果在函数名前加上static,则表示此函数只能在当前文件中被调用。
(3)未初始化数据区。亦称BSS区(uninitialized data segment),存入的是全局未初始化变量。BSS这个叫法是根据一个早期的汇编运算符而来,这个汇编运算符标志着一个块的开始。BSS区的数据在程序开始执行之前被内核初始化为0或者空指针(NULL)。例如一个不在任何函数内的声明:
1 long sum[1000];
将变量sum存储到未初始化数据区。
下图所示为可执行代码存储时结构和运行时结构的对照图。一个正在运行着的C编译程序占用的内存分为代码区、初始化数据区、未初始化数据区、堆区和栈区5个部分。
?
再来看一张图,多个一个命令行参数区:
(1)代码区(text segment)。代码区指令根据程序设计流程依次执行,对于顺序指令,则只会执行一次(每个进程),