C程序的内存分布

引子:

#include<stdio.h>
int main()
{ 
  char*p =”tiger”;
  p[1]=’I’;
  p++;
  printf(“%s\n”,p);
}

编译执行后提示:段错误

简单分析:

char *p ="tiger";  系统在栈上开辟了4个字节存储p的数值,其中"tiger"在只读存储区中存储,因此"tiger"的内容不能改变,*p="tiger",表示地址赋值,因此,p指向了只读存储区,因此改变p指向的内容会引起段错误。但是因为p本身内容是存放在栈上,因此p的数值是可以改变的,因此p++是正确的。

上述出现了栈、只读存储区 这些都是C程序中各个不同存储部分的名称,了解了C程序的存储分布可以有效的降低coding过程出现段错误的几率。

C程序经过编译-链接-重定位后就会生成一个有二进制机器代码组成的可执行文件,一般有如下几个部分组成:

.text 代码段

CPU执行的机器指令部分。代码段通常是可以共享的,所以在运行时被多个进程使用也只需有一个副本,另外,正文段常常是只读的,以防止程序由于意外事故而修改其自身的指令。另外,代码段还规定了局部变量申请内存空间的信息

.data 数据段

程序中被初始化的全局变量,静态变量以及字符串常量(即上述所说的只读存储区)

.bss 未初始化数据段

未初始化的全局或者静态变量放置于此。由于是未初始化,所以加载至内存后内核会将此段初始化为0

当程序加载至内存后有需要堆和栈来存放运行时存取的数据

堆 heap (动态存储区)

自下而上增长,一般有程序员自己分配(malloc)和释放(free),分配速度较慢,但由于是采用链式非连续地址的数据结构所以灵活度比较大,一般32bit系统下堆可以分配到4G内存,但容易产生内存碎片,关于则方面可以参考下linux的内存分配机制slab和buddy的有机结合

栈 stack

自顶向下增长,由系统自动分配,分配速度较快,由于是系统事先分配的连续地址内存会受限于OS预设的大小,超出即出现overflow,linux下可以使用ulimit -a查看当前栈大小和-s 设置栈带下。再栈中保存着函数调用的环境变量,在进行函数调用时入栈顺序为:函数调用完后需要执行的语句-->函数调用参数,一般是从右向左入栈-->最后就是函数的局部变量,函数调用完后再依次出栈

C程序内存分布图:

++++++++++++++++++++++  高地址

命令行参数和环境变量

++++++++++++++++++++++

栈, 向下增长

++++++++++++++++++++++

堆,向上增长

++++++++++++++++++++++

bss段

++++++++++++++++++++++

data段

++++++++++++++++++++++

text段

++++++++++++++++++++++ 低地址

大家可以使用objdump或者readelf来查看下ELF格式的程序中各个段的详细信息


你可能感兴趣的:(C程序的内存分布)