火善栋 杨旭东
(1.重庆三峡学院,重庆万州 404100;2.重庆安全技术职业学院,重庆万州 404120)
对于C/C++程序设计的内存管理,一般而言,我们可以简单地把内存分为三个部分:静态区、栈和堆.但是,很多初学者甚至是一些所谓的老手由于没有从本质上正确理解堆和栈之间的区别,经常把堆和栈混为一团,甚至认为堆和栈是同一个概念,这也是他们对C/C++编程中出现的某些错误或者某些结果百思不得其解的一个重要原因.其实,堆栈就是栈,而不是堆,堆和栈是两个完全不同的概念,堆和栈都有着各自不同的特征.正确理解这三者尤其是堆和栈在内存中的分布特点,对于正确编写高质量的C/C++程序有着至关重要的作用,本文借助汇编语言低级化的特点,试图通过一个简单的C++小程序从底层对其在内存中的分布情况及其特征作了比较详细的分析和探讨,以帮助读者正确理解这三者之间的联系和区别.
下面就通过一个简单的C++小程序来详细说明静态内存、栈内存和堆内存的内在区别和联系,该小程序定义了一个全局变量dd、一个静态的局部变量aa和一个用指针p定义的字符串常量(对应于静态内存)、一个普通数组bb[](对应于栈内存)和一个动态数组new int[3](对应于堆内存),然后分别对其作一些简单的操作,并在vc6.0环境下通过反汇编代码以展示其在内存中的分布情况,表1为该c++源程序和反汇编代码对照表.从表1中可以看出,static变量aa和全局变量dd、用指针p定义的字符串常量、普通数组bb[]和动态数组new int[3]并不是分布在同一块内存区域中.我们把static变量和用指针定义的字符串常量所分布的区域成为静态区,动态数组也就是用new操作符或malloc系列函数动态申请到的内存区域称为堆区,普通数组等其它普通局部变量等所分布的区域称为栈区.
当某一个函数要操作静态区中的数据时,对于 static变量或全局变量则直接通过调用其所在的内存地址对其操作,如示例中9和10代码片段所示所示,对于字符串常量则通过调用其所在的内存块的首地址(该首地址保存在调用函数的栈中)对其操作,如代码片段8所示;对于普通数组和普通的局部变量则直接保存在调用函数的栈中并对其进行操作,其过程最为简单和高效,如代码片段11和代码片段8、13和17部分指令所示;对于动态内存,则先要调用一系列相关的申请动态内存的函数(大部分反汇编代码省略),并将所申请到的动态内存的首地址通过 EAX返回保存到调用函数的栈中,然后通过这个首地址对堆中的内存和数据进行操作,如示例中代码片段13、14、15、16所示,由此可见,这一过程最有复杂但更加灵活.
表1 C++源代码和反汇编代码对照表
图1为示例中各个变量及其所在的内存区域分布结构示意图(所有内存区域从上到下依次增大).
说明:从图1中可以看出,从申请动态内存到最后释放动态内存,在栈中有三个dword字段同时存放着堆内存的首地址,看似不合理,实则这是由反汇编代码内部执行机制所造成的.
从图1中可以看出,栈内存数据的存放是以ebp指针为基准向着地址减小的方向存放的,当然,从表一中反汇编代码也可以看出,对栈内数据的操作也是以ebp为基准的;堆区是以堆内存的首地址为基准向着地址增大的方向存放的;静态区中 static变量是以第一个 static变量(或全局变量)开始向着地址增大的方向存放,而字符串常量则是存放在静态区中另一块区域,它与 static变量并不是连续存放的;字符串常量和堆区的首地址通过相关的局部变量保存在调用函数的堆栈中.
从以上分析和说明,可以验证和总结如下结论:
静态区、栈和堆分别属于计算机内存中三块不同的区域,静态区中的 static变量和全局变量由编译器在编译的时候分配(这从示例代码的反汇编代码7和8可以反应出来),它与栈并没有直接的联系,这也是静态区的内容在整个程序的生命周期内一直能够存在根本原因,静态区的字符串常量将其首地址保存在调用函数的堆栈中,调用函数通过这个首地址对该字符串进行操作.
栈保存局部变量(static局部变量除外),对栈内数据的操作和访问是通过ebp指针来进行的.栈上的内容只在函数的范围内存在,当函数运行结束时,栈内存会自动释放[2],其特点是简单执行效率高,这也是函数不能直接返回指向栈内存内容指针的根本原因;栈内的数据是按内存地址从大到小的顺序进行存放的.
堆是由malloc系列函数或new操作符分配到的内存,其首地址通过 EAX寄存器保存在操作该堆内存的函数的栈中,调用函数通过该首地址对堆内存进行操作,其过程比较复杂;栈内存必须通过free或delete函数进行释放,否则,其数据在整个程序的运行过程中一直有效[6];堆中的数据是按内存地址从小到大的顺序进行存放的.
[1]谭文,等.天书夜读:从汇编语言到 Windows内核编程[M].北京:电子工业出版社,2008.
[2]火善栋.通过汇编语言理解函数调用的内在机理[J].计算机时代,2010(7).
[3]吕凤翥.C++语言程序设计[M].北京:清华大学出版社,2003.
[4]卜艳萍.汇编语言程序设计教程[M].北京:清华大学出版社,2008.
[5]王晓东.C++程序设计简明教程[M].北京:中国水利水电出版社,2008.
[6]林锐.高质量程序设计指南——C++/C语言[M].北京:电子工业出版社,2003.