本节对堆和栈内存进行描述。
- 应用程序启动后,操作系统将整个程序加载到内存,分配相应的物理ram,确保程序可以正常运行。堆和栈是ram中存在的两个区域。栈通常是一个预定义大小的内存区域,一般是2M字节左右。堆也是预定了默认值的区域,但可以随着程序的运行变大。
-
#include <iostream> struct Vector3 { float x, y, z; Vector3() :x(1),y(2),z(3) {} }; int main() { //在栈上分配内存 int value = 5; //整数 int array[5]; //数组 for (int i = 0; i < 5; i++) { array[i] = i; } Vector3 vector; //类或者结构体 //在堆上分配,使用new操作符在堆上进行分配 int* hvalue = new int; *hvalue = 5; int* harray = new int[5]; for (int i = 0; i < 5; i++) { harray[i] = i+5; } Vector3* hvector = new Vector3; std::cin.get(); }
-
栈内存分配
- 下图是展示的内存地址是栈上array的内存地址,可以看到,在内存上市连续的20个字节的大小,因为一个int是4字节。
- 在array附近可以看到05 00 00 00,这是value的内存地址,中间多了一些字节是因为现在是在Debug模式下,中间添加的是安全守卫,在所有变量的周围都会添加,确保内存溢出不是改变所有变量等。
- 继续执行,下入红色的字节表示的是vector的字节,中间插入的仍是安全守卫。
-
堆内存分配
- 继续执行上述程序,在内存中可以看到hvalue的值以及内存地址
- 继续执行,查看harray的从,从下图可以看到和hvalue的内存地址相差很远。
- 在堆中申请内存,需要程序员自己去释放内存,而在栈中,超出作用域后会自动释放内存。如下所示:
-
#include <iostream> struct Vector3 { float x, y, z; Vector3() :x(1),y(2),z(3) {} }; int main() { //在栈上分配内存 int value = 5; //整数 int array[5]; //数组 for (int i = 0; i < 5; i++) { array[i] = i; } Vector3 vector; //类或者结构体 //在堆上分配,使用new操作符在堆上进行分配 int* hvalue = new int; *hvalue = 5; int* harray = new int[5]; for (int i = 0; i < 5; i++) { harray[i] = i+5; } Vector3* hvector = new Vector3; delete hvalue; delete[] harray; delete hvector; std::cin.get(); }
-
new操作符实际上调用了一个malloc的函数从堆上分配内存,程序会维护一个空闲链表,用来跟踪哪些内存块是空闲的。
-
栈分配比堆分配效率高的原因
-
在栈上分配内存仅仅是一条cpu指令,而在堆上, 需要执行很多操作,所以在栈上分配执行效率比在堆上分配高很多。下面通过查看生成的汇编代码来证实。
-
如上图显示,在通过栈给value分配内存是,仅仅需要执行一条cpu指令。
-
上图现在,在堆上则需要执行7条cpu指令,才能给hvalue分配内存。
-
生成汇编的设置方法如下: