-
栈:在函数内部声明的所有变量都将占用栈内存
-
堆:这是程序中未使用的内存,在程序运行时可用于动态分配内存
在C++中,可以使用new
运算符为给定类型的变量在运行时分配堆内的内存,这会返回所分配的空间地址。如果您不再需要动态分配的内存空间,可以使用delete
运算符,删除之前由new
运算符分配的内存。
new
的功能是在堆区新建一个对象,并返回该对象的指针。所谓的新建对象的意思就是,将调用该类的构造函数,因为如果不构造的话,就不能称之为一个对象。而 malloc
只是机械的分配一块内存,如果用mallco
在堆区创建一个对象的话,是不会调用构造函数的。
例如,我们用如下语法来为一个数组分配空间:
char* pvalue = NULL; // 初始化为 null 的指针
pvalue = new char[20]; // 为变量请求内存
使用完毕后需要删除上面创建的数组:
delete[] pvalue; // 删除 pvalue 所指向的数组
二维数组:
int **array
// 假定数组第一维长度为 m, 第二维长度为 n
// 动态分配空间
array = new int *[m];
for( int i=0; i < m; i++ ) {
array[i] = new int [n];
}
// 释放空间
for( int i=0; i < m; i++ ) {
delete[] arrar[i];
}
delete[] array;
这里注意在释放时要先对数组中的所有“行”进行释放,而且要用释放数组的关键字delete[]
,最后再释放本体。
内存泄漏
内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费。
内存泄漏会因为减少可用内存的数量从而降低计算机的性能。最终,在最糟糕的情况下,过多的可用内存被分配掉导致全部或部分设备停止正常工作,或者应用程序崩溃。内存泄漏带来的后果可能是不严重的,有时甚至能够被常规的手段检测出来。在现代操作系统中,一个应用程序使用的常规内存在程序终止时被释放。这表示一个短暂运行的应用程序中的内存泄漏不会导致严重后果。
当系统所有的内存全部耗完后(包括主内存和虚拟内存,在嵌入式系统中,仅有主内存),所有申请内存的操作将失败。这通常导致程序试图申请内存来终止自己,或造成分段内存访问错误(segmentation fault)。
以下例子中,存储了整数123的内存空间不能被删除,因为地址丢失了。这些空间已无法再使用。
int main() {
int *a = new int(123);
cout << *a << endl;
// We should write "delete a;" here
a = new int(456);
cout << *a << endl;
delete a;
return 0;
}
如果new
分配内存失败,会抛出bad_alloc
异常,但如果我们使用时在后面加上nothrow
关键词,则会返回一个空指针。
RAII
RAII全称为Resource Acquisition Is Initialization,它是在一些面向对象语言中的一种惯用法。
堆栈溢出
堆栈溢出(stack overflow)在计算机科学中是指使用过多的存储器时导致调用堆栈产生的溢出。堆栈溢出的产生是由于过多的函数调用,导致调用堆栈无法容纳这些调用的返回地址,一般在递归中产生。堆栈溢出很可能由无限递归(Infinite recursion)产生,比如:
int foo(){
return foo();
}
但也可能仅仅是过多的堆栈层级。