# C++内存分区,堆和栈的区别
# 简要回答
c++的内存分区从低地址到高地址分别是:
代码段:存储程序的机器指令(函数体),只读,可能共享。
数据段:存放未初始化的静态常量,全局变量
BSS段:未初始化的静态常量,全局变量以及初始化为0的全局变量
栈:适合存储生命周期较短,大小固定的对象,编译器自动分配释放,优点是高效且安全,但空间小
堆:适合存储生命周期较长,大小动态变化的对象,动态分配内存区域,由程序员手动管理,使用时要谨慎管理内存,空间大,但管理复杂,容易内存泄漏
# 详细回答
栈区:由编译器在需要的时候分配,在不需要的时候自动清除的变量存储区,里面的变量通常是局部变量、函数参数等
堆区:由new分配的内存块,他们的释放编译器不去管,由程序去控制,一般一个new就要对应一个delete
自由存储区:就是那些由malloc等分配的内存块,它和堆是十分相似的,不过它是用free来结束自己的生命的
全局/静态存储区:全局变量和静态变量被分配到同一块内存中,在C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区
常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改
代码区:存放在机器指令,只读,很安全
区分堆和栈
1.管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak
2.空间大小:一般来讲在32位系统下,堆内存可以达到4G的空间,从这个角度来看堆内存几乎是没有什么限制的。
但是对于栈来讲,一般都是有一定的空间大小的。
3.碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。
对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出,在他弹出之前,在他上面的后进的栈内容已经被弹出。
4.生长方向:对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。
5.分配方式:堆都是动态分配的,没有静态分配的堆,栈有2种分配方式:静态分配和动态分配。
静态分配是编译器完成的,比如局部变量的分配, 动态分配由 malloc 函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。
6.分配效率:堆的效率比栈要低得多。栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。
堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。
# 代码示例
#include <iostream>
using namespace std;
int global_var = 10; // 全局区
const int const_global = 20; // 常量区
void demo() {
int local_var = 30; // 栈区
int* heap_var = new int(40); // 堆区
cout << "local_var addr: " << &local_var << endl;
cout << "heap_var addr: " << heap_var << endl;
cout << "global_var addr: " << &global_var << endl;
cout << "const_global addr: " << &const_global << endl;
delete heap_var; // 不释放就内存泄漏
}
int main() {
demo();
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 知识拓展
内存图解

栈和堆的线程安全
栈是线程私有的:每个线程有自己的栈,天然线程安全。
堆是线程共享的:多个线程可能访问同一内存,因此要加锁或用原子操作保护。
- 面试官可能会追问的问题
平时你在项目中怎么管理内存?
答:作答时可以往使用智能指针、RAII原则、内存池等方案,针对自己具体项目进行解释。
评论
验证登录状态...