《UNIX环境高级编程》学习笔记——进程环境

来源:互联网 发布:尚学堂大数据百度网盘 编辑:程序博客网 时间:2024/05/17 04:55

C程序的存储空间布局

一个C程序包含下面几个部分:

  • 正文段。这是由CPU执行的机器指令组成。通常,正文段可共享,所以即使是频繁执行的程序(如文本编译器、C编译器和shell等)在存储器中也只需要一个副本,另外,正文段常常是只读的,以防止程序由于意外而修改其自身的指令。
  • 初始化数据段。通常将此段称为数据段,它包含了程序中需要明确地赋初值的变量。例如,C程序中出现在任何函数之外的声明

 int maxcount = 99; 

使此变量带有其初值存放在初始化数据段中。

  • 非初始化数据段。通常将此段成为bss段,这一名称来源于一个早期的汇编运算符,意思是"block started by symbol"(由符号开始的块),在程序开始执行之前,内核将此段中的数据初始化为0或空指针。出现在任何函数外的C声明

long sum[1000];

使此变量存放在非初始化数据段中。

  • 栈。自动变量以及每次函数调用时所需保存的信息都放在此段中。每次调用函数时,其返回地址以及调用者的环境信息(例如某些机器寄存器的值)都存放在栈中。然后,最近被调用的函数在栈上为其自动和临时变量分配存储空间。通过这种方式使用栈,可以递归调用C函数。递归函数每次调用自身时,就使用一个新的栈帧,因此一个函数调用实例中的变量不会影响另一个函数调用实例中的变量。
  • 堆。通常在堆中进行动态存储分配。

下图显示了一个C程序中各个段的逻辑布局:


典型的存储布局

内存分配

ISO C说明了三个用于内存分配的函数:


  1. malloc。分配指定字节数的存储区。此存储区中的初始值不确定。
  2. calloc。为指定数量具指定长度的对象分配存储空间。该空间中的每一位都初始化为0。
  3. realloc。更改以前分配区的长度(增加或减少)。当增加长度时,可能需要将以前分配区的内容移到另一个足够大的区域,以便在尾端提供增加的存储区,而新增区域内的初始值则不确定。

realloc函数使我们可以增、减以前分配区的长度(最常见的用法是增加该区)。例如,如果先为一个数组分配存储空间,该数组长度为512,然后在运行时填充它,但运行一段时间后发现该数组原先的长度不够用,此时就可以调用realloc扩充相应存储空间。如果在该存储区后有足够的空间可供扩充,则可以在原存储区位置上向高地址方向扩充,无需移动任何原先的内容,并返回传送给它的同样的指针值。如果在原存储区后没有足够的空间,则realloc分配另一个足够大的存储区,将现有的512个元素数组的内容复制到新分配的存储区。然后释放原存储区,返回新分配区的指针。

动态分配内存可能的错误:

  1. 在超过一个已分配区的尾端进行写操作,则会重写后一个块的管理记录。同样,在已分配区起始位置之前进行写操作会重写本块的管理记录。这种类型的错误是灾难性的。
  2. 释放一个已经释放了的块。
  3. 如果一个进程调用malloc函数,但却忘记调用free函数,那么该进程占用的存储区就会连续增加,这样会造成内存泄漏。



0 0