在学习
C程序设计语言时,会遇到两个很相似的术语:堆内存和
栈内存。这两个术语虽然只有
一字之差,但是所表达的意义还是有差别的,堆内存和栈内存的区别可以用如下的比喻来看出:使用堆内存就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。使用栈内存就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。操作系统中所说的堆内存和栈内存,在操作上有上述的特点,这里的堆内存实际上指的就是(满足堆内存性质的)
优先队列的一种
数据结构,第1个元素有最高的优先权;栈内存实际上就是满足先进后出的性质的数学或数据结构。
在标准
C语言上,使用
malloc等内存
分配函数获取内存即是从堆中分配内存,而在一个
函数体中例如定义一个数组之类的操作是从栈中分配内存。从堆中分配的内存需要程序员手动释放,如果不释放,而系统内存管理器又不自动回收这些堆内存的话(实现这一项功能的系统很少),那就一直被占用。如果一直申请堆内存,而不释放,内存会越来越少,很明显的结果是系统
变慢或者申请不到新的堆内存。而过度的申请堆内存(可以试试在函数中申请一个1G的数组!),会导致堆被压爆,结果是灾难性的。
我们掌握堆内存的权柄就是返回的指针,一旦丢掉了指针,便无法在我们视野内释放它。这便是
内存泄露。而如果在函数中申请一个数组,在函数体外调用使用这块堆内存,结果将无法预测。 我们知道在
c/c++ 中定义的数组大小必需要事先定义好,他们通常是分配在静态
内存空间或者是在
栈内存空间内的,但是在实际工作中,我们有时候却需要动态的为数组分配大小,这时就要用到堆内存分配的概念。在堆内存分配时首先应该知道操作系统有一个记录空闲内存地址的
链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的
空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的
delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。堆内存是向高地址扩展的数据结构,是
不连续的内存区域。这是由于系统是用链表来存储的空闲
内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆内存的大小受限于
计算机系统中有效的
虚拟内存。由此可见,堆内存获得的空间比较灵活,也比较大。堆内存是由new分配的内存,一般速度比较慢,而且容易产生
内存碎片,不过用起来最方便.另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,它直接在进程的
地址空间中保留一块内存,虽然用起来最不方便。但是速度快,也最灵活。
说明:如果分配成功则返回指向被分配内存的指针,否则返回空指针NULL。当内存不再使用时,应使用
free()函数将内存块释放。
malloc的语法是:指针名=(
数据类型*)malloc(长度),(数据类型*)表示指针.
使用
malloc函数分配内存时,
返回值要经过
类型转换才可赋予一个
指针变量。该函数如分配内存成功,则返回其始地址,否则返回NULL。
头文件为#include<
stdlib.h>。
new分配内存时不需要
类型转换。用new申请的空间必须要用delete释放。而且指针值不能改变。形式有:delete
指针变量名(可释放一个
内存单元)、delete[]指针变量名(可释放若干个内存单元)。
函数原形本身是void*malloc(
size_tsize),由于
动态分配的
空间计算机并不知道是用来做什么的所以是无类型的,但你要把它用在动态的整形数组上的时候就要显式的转换成int*了。