本文目录
- 1. C/C++的内存分布
- 1.1 分辨
- 1.2 sizeof与strlen区别
- 2. C的内存管理
- 3. C++的内存管理
- 3.1 new与delete、delete[]
- 3.2 operator new与operator delete
- 4. malloc/free与new/delete区别
- 5. 内存泄露
- 5.1 分类
- 5.2 避免内存泄露
1. C/C++的内存分布
int globalVar = 1;
static int staticGlobalVar = 1;void Test()
{static int staticVar = 1;int localVar = 1;int num1[10] = { 1, 2, 3, 4 };char char2[] = "abcd";const char* pChar3 = "abcd";int* ptr1 = (int*)malloc(sizeof(int) * 4);int* ptr2 = (int*)calloc(4, sizeof(int));int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);free(ptr1);free(ptr3);
}
1.1 分辨
四个选项:栈、堆、静态区/全局区(数据段)、常量区(代码段)。
globalVar在哪里? 静态区
staticGlobalVar在哪里?静态区
staticVar在哪里?静态区
localVar在哪里?栈
num1 在哪里?栈
char2在哪里?栈
*char2在哪里? 栈
pChar3在哪里? 栈
*pChar3在哪里?常量区
ptr1在哪里?栈
*ptr1在哪里?堆
- 内核空间:用户代码不能读写;
- 栈区:又叫堆栈,栈是向下增长的(从高地址到低址值向下使用);
- 内存映射段:文件映射、动态库、匿名映射;
- 堆区:程序运行时动态内存分配,可以向上增长。
- 数据段:存储全局变量和静态变量;
- 代码段:存储可执行代码和常量。
1.2 sizeof与strlen区别
sizeof(num1) 40
sizeof(char2) 5
strlen(char2) 4
sizeof(pChar3) 4或8
strlen(pChar3) 4
sizeof(ptr1) 4或8
sizeof计算内存存储大小;strlen计算字符串长度,不包含\0。
2. C的内存管理
申请内存:malloc、calloc、realloc;
释放内存:free
面试题:
-
malloc、calloc、realloc区别是什么?
malloc仅仅是申请一块内存;
calloc底层调用malloc申请一块内存,但还会额外对变量进行默认初始化;
realloc在原申请的内存基础上进行内存扩容,如果后面的内存空间够,则原地扩容;
后面的内存空间不够,则异地扩容,返回新的内存地址。 -
malloc实现原理
这个太难了,先不研究。
3. C++的内存管理
C++可以继续使用C的malloc、calloc、realloc和free,C的内存管理使用起来很麻烦,C++有自己的内存管理方式,使用起来很方便。
3.1 new与delete、delete[]
- new和delete都是操作符,new申请内存,delete/delete[]释放内存。
int* pa = new int;
int* pb = new int(12); // 动态申请内存并初始化
int* pArr = new int[10]; // 动态申请40个字节内存空间
delete pa;
delete pa;
delete[] pArr;
- 申请/释放单个不连续的内存使用new和delete,申请/释放多个连续的内存使用new[]和delete[]。
- new[]和delete[]底层多次调用new和delete完成申请或释放内存。
3.2 operator new与operator delete
- operator new和operator delete是C++提供的全局函数;
- new和delete是操作符,new和delete调用它们俩完成申请和释放内存;
- operator new实际是通过malloc来申请内存,operator delete最终也是通过free来释放内存。
4. malloc/free与new/delete区别
- new/delete对于自定义类型申请空间,会调用构造函数(new之后)和析构函数(delete之前),而malloc/free做不到。
- 对于内置类型,两者除了使用上有差别,效果一样。
- malloc/free是函数,new/delete是操作符。
- new申请内存失败会抛异常,malloc申请失败返回NULL。
- malloc申请的内存空间不会默认初始化,new会。
- malloc申请内存需要计算并传递内存大小,new不需要。
- malloc返回值是void*,接收时需要强转成需要的类型,new的返回值不需要强转。
5. 内存泄露
内存泄露:程序未能释放不再使用的内存。
不是指物理上的消失,而是因为这块内存不再使用,程序失去对这块内存的控制,造成内存浪费。对于长期运行的程序而言,如服务器、操作系统,内存泄漏造成的影响很大,最终程序响应越来越慢,导致机器卡死,所以及时释放不需要再使用的内存至关重要。
需要注意的是避免内存泄露的同时,也要避免使用野指针。
5.1 分类
- 堆内存泄露(Heap Leak):malloc/calloc/realloc/new申请的内存没有被free/delete。
- 系统资源泄露:程序使用系统分配的资源,如套接字、文件描述符、管道等,之后没有使用对应的函数释放资源。
5.2 避免内存泄露
- 检测内存泄漏:VS环境下使用Windows提供的
_CrtDumpMemoryLeaks()
函数,会提示泄露多少字节,但没有准确的位置信息。 - 内存泄露检测工具:很多工具都不靠谱。Linux下几款C++程序中的内存泄露检查工具 ----- 内存泄露检测工具比较
- 事前预防:最理想的情况,有良好的编码习惯,使用智能指针等。