BSS段、数据段、代码段、堆栈段

转自:http://blog.csdn.net/jxhui23/article/details/8064766


BSS段、数据段、代码段

可执行程序包括BSS段、数据段、代码段(也称文本段)。

BSS(Block Started by Symbol)通常是指用来存放程序中未初始化的全局变量和静态变量的一块内存区域。特点是:可读写的,在程序执行之前BSS段会自动清0。所以,未初始的全局变量在程序执行之前已经成0了。

在采用段式内存管理的架构中,数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。

代码段(code segment / text segment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许自修改程序。

是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)。

又称堆栈, 是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进后出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。

用c编译两个小程序如下:

程序1:

int ar[30000];  //BSS段
void main()
{
   ......
}

 

程序2:

int ar[300000] =  {1, 2, 3, 4, 5, 6 };  //代码段
void main()
{
   ......
}


发现程序2编译之后所得的.exe文件比程序1的要大得多。

汇编后发现区别很明显,一个位于.bss段,而另一个位于.data段,两者的区别在于:全局的未初始化变量存在于.bss段中,具体体现为一个占位符;全局的已初始化变量存于.data段中;而函数内的自动变量都在栈上分配空间。.bss是不占用.exe文件空间的,其内容由操作系统初始化(清零);而.data却需要占用,其内容由程序初始化,因此造成了上述情况。

总结:bss段(未手动初始化的数据)并不给该段的数据分配空间,只是记录数据所需空间的大小。

data(已手动初始化的数据)段则为数据分配空间,数据保存在目标文件中。

数据段包含经过初始化的全局变量以及它们的值。BSS段的大小从可执行文件中得到 ,然后链接器得到这个大小的内存块,紧跟在数据段后面。当这个内存区进入程序的地址空间后全部清零。包含数据段和BSS段的整个区段此时通常称为数据区。

*******************************************************************************************************************

例子:

#include <stdio.h>

int main(void *arg) {
  char *p1 = "Hello World";
  char p2[] = "Hello World";
  char *p3 = "Hello World";
  
  printf("p1 = 0x%08X, p2 = 0x%08X, p3 = 0x%08X\n", p1, p2, p3);

  p2[2] = 'A';
  printf("*p2 = %s\n", p2);

  p1[2] = "A";
  printf("*p2 = %s\n", p2);
}
输出结果:

p1 = 0x00400630, p2 = 0x6B664190, p3 = 0x00400630
*p2 = HeAlo World
Segmentation fault (core dumped)
原因:

1. p1和p2都是指针,存在栈内;p1指向的“Hello World”为字符串常量,存在静态存储区,而p2为数组首地址,数组内容为字符串"Hello World",数组内容是可以修改的。

2. p1和p3指向静态存储区的同一个字符串,所以地址相同。

3. 因为p1指向的为字符串常量,不可修改,所以p2[2]=‘A'会出错。


堆与栈的区别:转自http://blog.csdn.net/Stephen_yu/article/details/13773461

希望大家记住下面的规则:

      【规则1】用malloc 或new 申请内存之后,应该立即检查指针值是否为NULL。防止使用指针值为NULL 的内存。
     【规则2】不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。
     【规则3】避免数组或指针的下标越界,特别要当心发生“多1”或者“少1”操作。
     【规则4】动态内存的申请与释放必须配对,防止内存泄漏。
     【规则5】用free 或delete 释放了内存之后,立即将指针设置为NULL,防止产生“野指针”。

堆与栈的讨论:
管理方式:
   堆中资源由程序员控制(容易产生memory leak)。
   栈资源由编译器自动管理,无需手工控制。

系统响应:
   对于堆,应知道系统有一个记录空闲内存地址的链表,当系统收到程序申请时,遍历该链表,寻找第一个空间大于申请空间的堆结点,删除空闲结点链表中的该结点,并将该结点空间分配给程序(大多数系统会在这块内存空间首地址记录本次分配的大小,这样delete才能正确释放本内存空间,另外系统会将多余的部分重新放入空闲链表中)。
   对于栈,只要栈的剩余空间大于所申请空间,系统为程序提供内存,否则报异常提示栈溢出。

空间大小:
   堆是不连续的内存区域(因为系统是用链表来存储空闲内存地址,自然不是连续的),堆大小受限于计算机系统中有效的虚拟内存(32bit系统理论上是4G),所以堆的空间比较灵活,比较大。
   栈是一块连续的内存区域,大小是操作系统预定好的,windows下栈大小是2M(也有是1M,在编译时确定,VC中可设置)。

碎片问题:
   对于堆,频繁的new/delete会造成大量碎片,使程序效率降低。
   对于栈,它是一个先进后出的队列,进出一一对应,不会产生碎片。

生长方向:
   堆向上,向高地址方向增长。
   栈向下,向低地址方向增长。

分配方式:
   堆都是动态分配(没有静态分配的堆)。
   栈有静态分配和动态分配,静态分配由编译器完成(如局部变量分配),动态分配由alloca函数分配,但栈的动态分配的资源由编译器进行释放,无需程序员实现。

分配效率:
   堆由C/C++函数库提供,机制很复杂。所以堆的效率比栈低很多。
   栈是极其系统提供的数据结构,计算机在底层对栈提供支持,分配专门寄存器存放栈地址,栈操作有专门指令


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值