一般而言,分配给进程的内存有四个概念上不同的区域,分别为:代码段、数据段、堆和栈,其中数据段又可以细分为初始化为非零的数据和初始化为零的数据。如下图所示:

            -------------------

            |       程序栈     |----------高地址--〉低地址

            -------------------

            |          堆      |----------向上增长

            -------------------

            |          BSS     |----------数据段

            | 全局和静态变量   |

            -------------------  ----------低地址

            |     可执行代码   |----------代码段

            -------------------

      可执行指令放在代码段中,任何时刻,内存中只有一份相同程序的指令拷贝,多个实例共享这些代码。

      初始化为非零的静态数据和全局数据存放在数据段中,运行相同程序的每个进程,有自己的数据段。

      初始化为零的全局数据和静态分配数据存放在进程的BSS区域中,每个运行的进程都有自己的BSS,程序运行的时候,将数据放到数据段中,由此可知,只有初 始化为非零的变量才占用空间,所以对于类似static int ss[1024];这样的数组自动用0来填充,它占的空间很小。

      BBS,(二进制文件术语)是“Block Started by Symbol”的缩写,意为“以符号开始的块”.BSS是Unix链接器产生的未初始化数据段。其他的段分别是包含程序代码的“text”段和包含已初始化数据的“data”段。BSS段的变量只有 名称和大小却没有值。此名后来被许多文件格式使用,包括PE。“以符号开始的块”指的是编译器处理未初始化数据的地方。BSS节不包含任何数据,只是简单 的维护开始和结束的地址,以便内存区能在运行时被有效地清零。BSS节在应用程序的二进制映象文件中并不存在。
在采用段式内存管理的架构中(比如intel的80x86系统),bss段(Block Started by Symbol segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域,一般在初始化时bss 段部分将会清零。bss段属于静态内存分配,即程序一开始就将其清零了。
比如,在C语言之类的程序编译完成之后,已初始化的全局变量保存在.data 段中,未初始化的全局变量保存在.bss 段中。
text和data段都在可执行文件中(在嵌入式系统里一般是固化在镜像文件中),由系统从可执行文件中加载;而bss段不在可执行文件中,由系统初始化。

      堆,动态内存来自于堆,即:通过malloc得到的空间,通常情况下,堆是向上增长的,即:后面分配的地址比前面的地址在数值上大一些。

      栈,分配本地变量的地方,函数参数、函数的返回值和返回地址也放在栈空间中,需要特别注意的是,当函数返回后,存储在栈空间中的函数变量“自动消失”,空间被其他函数使用。栈空间是向下增长的。

      在C语言中,一般通过malloc/calloc函数分配空间,通过free()函数释放空间,使用realloc()改变已分配空间的大小。

      分配内存的步骤:

      1.申明一个指定类型的指针

      2.计算要分配空间的大小,一般使用函数sizeof()来实现

      3.调用函数malloc()完成空间的申请,将函数的返回值赋给指针变量,

      4.检查返回值是否不为NULL,保证空间分配成功

      5.分配好的空间是没有经过初始化的,其中可能包含一些垃圾信息,因此

         调用函数memset()将其用0来填充是个好的习惯

       释放内存步骤:

       1.调用函数free()释放掉空间

       注意:1.不可以使用free()掉后的空间

                2.free()后,最好将指针置为NULL,因为如果不做这步处理,

                   原来的指针依旧指向刚才释放的空间,可以继续操作

                3.避免重复释放空间

       在Unix系统上,提供了函数alloca()函数,可以实现在栈空间上分配指定大小的空间,这样的好处是,函数结束后,空间自动释放,不必显式地调用函数free(),但是该函数有很多弊端,比如不可移植等,因此不建议使用。

           有必要提一下malloc、calloc、realloc函数的底层实现,在Linux系统中,提供了brk()和sbrk()函数,上面几个函数就是在这两个函数的基础上实现的。

int *p = (int*)malloc(20);//动态在堆区分配空间,(空间内容初始值为随机值)必须人为释放
 //free(p);;

 int *p2 = (int*)alloca(20);//动态在栈区分配空间(空间内容初始值为随机值),自动释放。

 int *p3 = (int *)calloc(4,5);//动态在堆区分配空间,(空间内容初始值为0)必须人为释放
 free(p3); p3 = NULL;
 
 int *p4 = (int*)realloc(p,30);////动态在堆区扩充内存空间,(空间内容初始值为随机值)必须人为释放
 free(p4); p4 = NULL;

  char *p5 = "hello";
 char *p6 = "hello";

*p5 == *p6  因为 "hello" 是字符串常量,定义后会在常量去开辟一块空间存储hello,

因为是在常量区不可修改,所以没必要再从新申请一块新空间去存储另一个"hello",所以,

p5,p6指的是一块区域.

 char p7[] = "hello";
 char p8[] = "hello";

就完全不一样了,因为这是在栈区申请的区域,所以是不同的两块空间.