堆 栈内存生长方向

时间:2024-03-31 22:28:17

堆栈和内存增长方向问题:

堆:生长方向是向上的,也就是向着内存地址增加的方向。通常我们在画内存四区图时,堆的开口是向上的。

栈:它的生长方式是向下的,是向着内存地址减小的方向增长。栈的开口是向下的,上面的底部是栈底,下面的开口是栈顶。

在内存中,“堆”和“栈”共用全部的*空间,只不过各自的起始地址和增长方向不同,它们之间并没有一个固定的界限,如果在运行时,“堆”和 “栈”增长到发生了相互覆盖时,称为“栈堆冲突”,系统崩溃。
 

栈的增长方向与栈帧布局

这个上下文里说的“栈”是函数调用栈,是以“栈帧”(stack frame)为单位的。
每一次函数调用会在栈上分配一个新的栈帧,在这次函数调用结束时释放其空间。
被调用函数(callee)的栈帧相对调用函数(caller)的栈帧的位置反映了栈的增长方向:如果被调用函数的栈帧比调用函数的在更低的地址,那么栈就是向下增长;反之则是向上增长。

而在一个栈帧内,局部变量是如何分布到栈帧里的(所谓栈帧布局,stack frame layout),这完全是编译器的*。
至于数组元素与栈的增长方向:C与C++语言规范都规定了数组元素是分布在连续递增的地址上的。引用C语言规范的规定:

An array type describes a contiguously allocated nonempty set of objects with a particular member object type, called the element type.
A postfix expression followed by an expression in square brackets [] is a subscripted designation of an element of an array object. The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2))). Because of the conversion rules that apply to the binary + operator, if E1 is an array object (equivalently, a pointer to the initial element of an array object) and E2 is an integer, E1[E2] designates the E2-th element of E1 (counting from zero).

其实double a0[4]这个声明告诉编译器的是:我需要在栈帧里分配一块连续的空间,大小为sizeof(double)*4,并且让a0引用该空间的起始位置(最低地址);
而不是说:我要根据栈的增长方向,先分配a0[0],然后分配a0[1],再分配a0[2],最后分配a0[3],于是如果栈是向下增长那a0[1]就应该比a0[0]在更低的地址——不是这样的。

所以在题主给的例子里,a0和a1这两个分配在栈帧里的数组到底哪个在高地址哪个在低地址,其实并不反映栈的增长方向,而只反映了编译器自己的决定。
C与C++语言的数组元素要分配在连续递增的地址上,也不反映栈的增长方向。

 

堆 栈内存生长方向