专题-c++内存管理

                                                                             内存管理

1.       C++内存布局

[1]     在C++中,内存区分为5个区,分别是栈区,堆区,全局区(静态区), 常量区,代码区。

[2]     栈:局部变量和函数参数,由操作系统和编译器自动分配/释放

[3]     堆:程序员自己创建并维护,如果程序员忘记释放堆内存,会造成内存泄漏

[4]     全局区:全局变量和静态变量

2.       newmalloc

[1]     申请的内存所在位置:new操作符从自由存储区(free store)上为对象动态分配内存空间,而malloc函数从堆上动态分配内存。

[2]     返回类型安全性:new操作符内存分配成功时,返回的是对象类型的指针;而malloc内存分配成功则是返回void *。

[3]     内存分配失败时的返回值:new内存分配失败时,先调用用户指定的错误处理函数,这就是new-handler,会抛出bac_alloc异常;malloc分配内存失败时返回NULL

[4]     是否调用构造函数/析构函数:new,内存分配-构造函数-返回指针,delete,析构函数-释放内存;malloc/free(需要调用构造析构的函数不适合)不会调用构造函数/析构函数

[5]     new的实现可以基于malloc。

[6]     opeartor new /operator delete可以被重载

[7]     重新分配内存:使用malloc分配的内存后,如果在使用过程中发现内存不足,可以使用realloc函数进行内存重新分配实现内存的扩充。

[8]     是否需要指定内存大小:使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算,而malloc则需要显式地指出所需内存的尺寸

3.       堆和栈的区别

[1]     管理方式:栈由编译器自动分配和释放,而堆需要程序员来手动分配和释放,若忘记delete,容易产生内存泄漏。

[2]     空间大小:栈的内存空间是连续的,空间大小通常是系统预先规定好的,即栈顶地址和最大空间是确定的;而堆得内存空间是不连续的,由一个记录空间空间的链表负责管理,因此内存空间几乎没有限制,在32位系统下,内存空间大小可达到4G

[3]     生长方向不同:对于栈,他是向着内存地址减小的方向生长的,这也是为什么栈的内存空间是有限的;而堆是向着内存地址增大的方向生长的

[4]     碎片问题:由于栈的内存空间是连续的,先进后出的方式保证不会产生零碎的空间;而堆分配方式是每次在空闲链表中遍历到第一个大于申请空间的节点,每次分配的空间大小一般不会正好等于申请的内存大小,频繁的new操作势必会产生大量的空间碎片

[5]     分配效率:栈属于机器系统提供的数据结构,计算机会在底层对栈提供支持,出栈进栈由专门的指令执行,因此效率较高。而堆是c/c++函数库提供的,当申请空间时需要按照一定的算法搜索足够大小的内存空间,当没有足够的空间时,还需要额外的处理,因此效率较低。

(转自:https://www.cnblogs.com/mrlsx/p/5411874.html

4.       野指针

[1]     指针变量没有被初始化

[2]     指针p被free或者delete之后,没有置为NULL

[3]     指针操作超越了变量的作用范围

5.       结构体的内存对齐

[1]     为什么要对齐:为了减少使用的内存;为了提升数据读取的效率

[2]     实例:struct Test{char a; int b; short c;}; char类型的对齐值为1, int的对齐值为4, short的对齐值为2,整个结构体的对齐值为4,结果为:(1+3)+4+2=10 ,10+2=3*4;

6.       内存泄漏

[1]     内存泄漏指的是在程序里动态申请的内存在使用完后,没有进行释放:堆内存泄漏,系统资源泄露(handle ,SOCKET等)

7.       如何防止内存泄漏

[1]     显性的 new/ delete, malloc/ free是否匹配

[2]     构造函数中动态申请的内存,析构函数中是否释放

[3]     多态,析构函数为virtual

[4]     智能指针,shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存。在最后一个shared_ptr析构的时候,内存才会被释放。

[5]     DEBUG, 内存泄漏时提示的内存分配序号, 根据序号指定中断程序,打开堆栈调用窗口,定位泄漏位置,释放内存。(每当申请一块内存后,把指向它的指针加入到List中,当释放时,再把对应的指针从List中删除,到程序最后检查List就可以知道有没有内存泄露了)

posted @ 2019-07-31 14:53  行走的算法  阅读(170)  评论(0编辑  收藏  举报