个人技术分享

前面一节说到了,使用堆空间的速度要比栈空间慢,我们从几个方面来说明一些这个原因。

首先,堆空间和栈空间都在内存上面,它两个是内存上的两个不同的区域。

1. 从分配方式方面

栈空间 

  • 首先来说栈内内存
    我们的局部变量等都是存储在站内存上面的, 函数的调用也依赖于栈空间,线程等都离不开栈。那么栈空间的分配是怎么样的呢?

    简单来说它就是利用一个空间指针来分配空间的。 如图:

图一: 

 

假设我们要分配四字节的空间 

图二: 

 

如图,空间指针就会向后偏移4个字节,前面的空间就是分配的空间。如果分配的空间被释放,只需要将指针移动会原来的位置就行。(只需移动指针,释放内存中存放的数据并不用删除

  • 对于分配的栈空间,其周围会有一些没有初始化的空间(内存中都为c),用来确定范围,就是判断我们访问内存是是否越界,是一种安全机制。 
  • 而且相邻定义的局部变量在栈内存中是距离很近的。

 堆空间

  • 堆空间 
    首先堆空间的开辟是使用new运算符的,其实new运算符底层会去先访问C语言的malloc函数,然后去开辟空间。

    这些函数(malloc,realloc,calloc,free)会维护一个空闲列表(可用内存池),内部存放了一些指向空闲空间的指针,当我们申请开辟堆空间的时候,这些函数会先到空闲列表中去查找空间至少>=我们申请的空间大小的空间指针。

    然后,返回这个指针,如果,没有找到符合要求的,malloc函数会像操作系统请求,要求得到更多的内存,并在这块新内存上分配任务。如果操作系统无法像malloc提供更多的内存,那么malloc函数会返回NULL的空指针。从这个操作上来看,就可以看出堆空间的效率低了(因为栈空间开辟空间只需要向后移动空间指针就行)
  • 而且堆空间存储的数据不是相邻的,返回的是指向空间的指针,所以这些空间并不是连续的(比如说链表)。
  • 而且当我们调用delete去释放空间的时候,其底层会调用C语言的free(),而且,当释放空间的时候,会删除掉在内存中的数据。(栈是不需要删除数据的)

2. 从vs的内存调试窗口来说明 

我们查看下面代码的内存情况 

int main() {
	int value = 5;
	int array[5] = { 1,2,3,4,5 };

	int* hvalue = new int(10);
	int* harray = new int[5] {11, 12, 13, 14, 15};

	std::cin.get();
	return 0;
}

我们打一个断点,进入调试模式,在调试->窗口->内存->内存1。 

栈内存

 在视图的上面写上&value就可以查看到它的内存了

 

按下回车键,会发现内存中都是cccc,我们前面说了,在内存没有初始化的时候,内存中的值都是c。(因为我们在value初始化的位置打了断点,这条语句还没有执行,我们按F11往下执行) 

 你会发现,右侧的箭头指向了下一行语句,说明value的初始化语句已经执行了,可以看到视图中对应的位置,内存中存放了4个字节的数据,值就是5。

我们再来看array数组的 ,还是一样在上面的框中写入array(因为array本身就是指针所以不用写取地址符),然后我们再往下执行,让数据初始化。

 你会发现红色的部分就是数组的所有元素,你在这些数据向上看,你会注意到value的栈内存为止距离array的不远。

再来看一看栈内存的释放,我们将变量value放到一个块中,这样在块结束之后其就会释放。

同样执行上面的步骤,查看value的地址 ,并且让代码向下执行

你会发现,我们value变量已经释放了,但是原来内存中的值还没有修改,当下次再使用这块空间的时候再将里面的数据覆盖。

堆内存 

同样的道理访问下面的堆内存,直接写hvalue和harray就行 

hvalue的堆内存 

harray的堆内存 

你会发现,这两个空间相距很远,距离并不近。 

堆内存释放 

删除前: 

删除后 :

 你会发现删除之后,存储在堆空间的原来的数据已经被删除了。

3. 使用汇编代码查看 

同样在调试的情况下,右键选择转到反汇编,查看分配空间时候的汇编代码

value栈空间的汇编代码 

你会发现,它仅仅使用了一条指令而已。

hvalue堆空间的汇编代码

 你会发现,同样是开辟空间在栈上只需要一条指令,而在堆上呢?(至于数组和空间释放的对比,其实是类似的,可以自行查看)

总结

所以堆空间和栈空间的区别主要在分配,这也能直观的看出为什么栈空间的效率高,所以我们应该优先选择栈空间,当然如果需要用到堆空间的时候,依然要使用堆空间。(例如: 需要大空间,变量的生命周期由自己控制,函数返回数据等等)。