现在的位置: 首页 > 综合 > 正文

进程环境与进程控制(2): 堆和栈

2012年10月04日 ⁄ 综合 ⁄ 共 1365字 ⁄ 字号 评论关闭

1.  C/C++编译的程序, 内存分为以下几个部分(从低地址到高地址):
代码(text): 在可用内存的最低地址区, 存放程序函数的二进制代码和程序中所使用的常量, 函数调用是通过函数地址实现的.

全局已初始化数据(initialized data): 包括已初始化变量和已初始化的静态变量, 程序结束后自动释放.

全局未初始化数据(uninitialized data): 包括未初始化变量和未初始化的静态变量, 编译器会在编译器为这些变量初始化为0, 程序结束后自动释放.

棧(stack): 棧底在内存的高地址区, 由高地址向低地址增长. 棧由编译器负责申请和释放, 主要存放函数的参数, 局部变量等. 通常来说, 进程的棧容量很有限, 棧的生存周期有限, 这正是可以自动释放的原因.
如: 存在一个class Student, 创建一个局部对象Student st;
这个对象会在生存周期结束时自动调用析构函数, 释放该对象所占内存.

堆(heap): 堆在内存的低地址区, 由低地址向高地址增长. 堆由程序员手动申请和释放, 如果申请的内存不释放, 会造成内存泄露. 同时优点是我们可以决定堆内变量(对象)存在的时间, 对堆的操作对程序员是可见的, 只要我们保证释放就可以了. 注意: 一般情况下, 哪里申请的内存就要在哪里释放, 也就是说不要在A函数内申请的内存在B函数内释放, 这样是很危险的.

命令行参数和环境变量: 这在可用内存的最高地址区, 存储包括命令行参数, 环境变量等, 自动释放.

2. 示例代码:
这是一个前辈写的,非常详细
//main.cpp
int a = 0; 全局初始化区
char *p1; 全局未初始化区
main()
{
int b; 栈
char s[] = "abc"; 栈
char *p2; 栈
char *p3 = "123456"; 123456/0在常量区(text),p3在栈上。
static int c =0; 全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); 123456/0放在常量区(text),编译器可能会将它与p3所指向的"123456"优化成一个地方。
}

3. 堆和棧各自的优缺点:
堆的分配没有大小限制, 在32位系统上的限制是4GB;
而棧的大小是有限制的, 一般只能到几MB大小.

棧的分配效率很高,而且不会造成内存碎片;
而堆的分配效率不高, 大量的进行new/delete操作会造成大量的内存碎片.

棧中内存的释放是由编译器自己处理的;
而堆中内存的释放是由程序员手工处理的, 如果不释放会造成内存泄露.

构建在内存池管理上的程序可以优化这点, 它会把delete之后的内存保存在表里, 当需要new的时候先去表中查看, 如果有合适的空间就用, 如果没有合适的再进行new操作. 关于内存池这门很复杂的技术, 包括它的申请顺序, 大小匹配, 检索方法和回收机制, 以后有机会的话我会写相关的文章.

4. 小结:
在很多BBS流行着这样一句话,
堆和栈的区别可以用如下的比喻来看出:
使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。
使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。

抱歉!评论已关闭.