C++内存管理:
变量和对象在内存中的分配都是编译器在编译程序时安排好的,但同样带来了不便,如数组必须大开小用,指针必须指向一个已经存在的变量或对象。动态内存分配解决了这个问题。
C/C++定义了4个内存区间:代码区,全局数据区,栈区,堆区。定义变量是在编译程序的时候就进行的静态存储分配,所有的动态分配基本都是在堆区进行的。不过是不能说的这么绝对的,与编译器和库都是有关联的。函数的参数未必通过堆栈进行分配,这与具体的编译器都是有关的。而对于内存分配失败时的返回值也不一定为NULL,很多的编译器都可以捕获new操作符抛出的异常。
全局数据区 | 代码区 | 栈区 | 堆区 |
---|---|---|---|
data | code | stack | heap |
全局变量 | 函数 | 局部变量 | new,delete申请的空间 |
静态数据 | 函数参数 | ||
常量 | 返回地址 | ||
返回数据 |
堆内存的分配和释放是重复利用有限的资源的关键。
**指针变量名 = new 类型名(初始值);
delete 指针名;**
new运算符返回的是一个指向所分配类型变量(对象)的指针,而动态创建的对象本身没有标识符名。new表达式会从堆区分配对象,然后用括号中的值初始化改对象。而从堆区分配对象时,new表达式调用库操作符new()。例如:
int *pi = new int(0);
注意在内存分配失败的时候,通常会返回零值(与具体使用的库有关),所以要在动态分配内存的时候对返回的指针进行检查。
当使用delete操作符时,只是释放了指针所指向的内存空间,但指针本身没有撤销,指针所占用的内存空间并没有释放。
char *pc = new char;
*pc = ‘a‘;
int *pi = new int(8);
栈区 | 堆区 |
---|---|
pc | a |
pi | 8 |
但该函数或程序执行完毕后系统弹栈,pc和pi这两个变量将消失,但他们指向的堆区的内存不会自动释放,那么该内存将不能使用,除非系统重启。
写保护的方法:
char *pc = new char;
*pc = ‘a‘;
int *pi = new int(8);
if (pc) {
delete pc;
}
if (pi) {
delete pi;
}
char *string = new char[20];
if (string == 0) {
return;
}
/* ... */
delete []string;
变量的分配并非在编译期间生成:
(1)全局变量和静态变量在编译时是在以初始化数据段或未初始化数据段内分配;
(2)局部变量是在执行期间从栈中分配;
(3)类中的成员变量是在类被实例化时被分配。
扩展知识
1、sizeof操作符
说到C++的内存就让我想到sizeof操作符,这里稍微细点说。sizeof是C/C++的一个操作符,用来返回一个对象或者类型所占的内存字节数,返回值的类型是size_t(typedef)。
语法形式:
(1)sizeof(object);
(2)sizeof(type_name);
(3)sizeof object;
sizeof在计算对象的大小的时候也是把对象转换为类型来进行计算的,如果传入表达式和函数,sizeof计算的是表达式结果类型和函数返回类型的大小,函数和表达式本身是不会被调用的。
sizeof的计算发生在编译的时候,所以可以把它当作是常量表达式来使用:
char array[sizeof(int) * 10];
对于基本数据类型的sizeof一般没有什么问题,如果是指针就需要注意点了,因为指针只是记录对象的地址,也就是计算机内部地址总线的宽度,数组的sizeof值等于数组所占的内存字节数,需要注意的是当数组是型参的时候,数组名称是当指针使用的。
char a1[] = "adb";
int a2[3];
sizeof(a1); //结果是4
sizeof(a2); //结果是12
关于struct的sizeof就涉及到了C/C++的数据对齐问题了,可以去看我之前的文章有详细的讲解。
2、内存管理的变革
C/C++语言的内存管理经历过几次的变革,不过直到现在还是没能够趋于成熟。
(1)从malloc/free到new/delete。这次的变革是当时OOP技术兴起的产物。因为C++是强类型语言,new/delete的主要成果是加强类型的观念,减少强制类型转换的需求。但是对于内存管理来说,这次的变革并没有多大的突破性;
(2)从new/delete到内存配置器(allocator)。从STL被纳入C++标准库之后,allocator也就被引入到C++的内存管理中,整个STL的所有组件的内存都是从allocator分配,STL本身是不推荐使用new/delete进行内存管理,而是推荐使用allocator。但是allocator的引入并没有改变传统C++程序员的观念,大部分人在使用STL的同时,依旧是在使用new/delete在进行繁琐的内存分配/释放的过程。
主要的原因有两。一是STL设计者主要可能还是出于将内存管理从容器的实现独立出来,使得STL使用者在内存管理算法上有选择的余地,设计者本身可能也没意识到allocator的重要性。二是allocator本身也是侧重于关注效率上,并没有侧重于C++语言使用者对内存管理观念上的变革。
原文地址:http://blog.csdn.net/john_cdy/article/details/45476989