学习目标:了解C/C 内存的分段情况,C 内容管理方式、operator new与operator delete函数 、new和delete的实现原理、定位new的表达式、最后介绍相关面试题的解析
文章目录- 一、C/C 内存分段
- 二、C语言中动态内存管理方式
- 三、C 内存管理方式
- 1.new/delete操作内置类型
- 2 new和delete操作自定义类型
- 四、operator new与operator delete函数
- 五、new和delete的实现原理
- 1.内置类型
- 2.自定义类型
- 六、定位new表达式(placement-new)
- 七、常见面试题
- 1 malloc/free和new/delete的区别
- 2 内存泄漏
- 2.1什么是内存泄漏
- 2.2内存泄漏分类(了解)
- 2.3 如何检测内存泄漏(了解)
- 2.4如何避免内存泄漏
- 1.new/delete操作内置类型
- 2 new和delete操作自定义类型
- 1.内置类型
- 2.自定义类型
- 1 malloc/free和new/delete的区别
- 2 内存泄漏
- 2.1什么是内存泄漏
- 2.2内存泄漏分类(了解)
- 2.3 如何检测内存泄漏(了解)
- 2.4如何避免内存泄漏
一、C/C 内存分段
C/C 程序会对内存进行分段。
从C语言的角度我们知道:分为栈、堆和静态区:
从操作系统的角度我们分为:
对于不同的区域数据有不同的性质,方便管理。
- 栈又叫堆栈,非静态局部变量/函数参数/返回值等等,栈是向下增长的>。
- 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。
- 堆用于程序运行时动态内存分配,堆是可以上增长的。
- 数据段–存储全局数据和静态数据。
- 代码段–可执行的代码/只读常量。
我们先来看下面的一段代码和相关问题,直接进行灵魂拷问:
代码语言:javascript复制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);
}
globalVar在哪里?全局变量,在数据段(静态区)
staticGlobalVar在哪里?静态变量,在数据段(静态区)
staticVar在哪里?数据段(静态区)
localVar在哪里?局部变量,在栈
num1 在哪里?栈
—————————————————————————————————
char2在哪里?栈
*char2在哪里?"abcd"常量在代码段中,char2在栈中开辟一个数组,在把常量拷贝到数组中去,*char就是a,a在栈中
pChar3在哪里?pChar3是局部变量,是常变量,还是在栈中
*pChar3在哪里?pChar3是一个指针(也就是"abcd"的地址),故*pChar3在代码段(常量区)中
ptr1在哪里?ptr1是一个局部变量的指针,指向在堆上动态开辟的空间,所以ptr1在是在栈上的
*ptr1在哪里?*ptr1在堆上,在堆
sizeof(num1) = 40;
sizeof(char2) = 5;
strlen(char2) = 4;
sizeof(pChar3) = 4/8;
strlen(pChar3) = 4;
sizeof(ptr1) = 4/8;
至此,结束我们的这一道题。
二、C语言中动态内存管理方式
malloc/calloc/realloc和free
代码语言:javascript复制void Test ()
{
int* p1 = (int*) malloc(sizeof(int));
free(p1);
// 1.malloc/calloc/realloc的区别是什么?
int* p2 = (int*)calloc(4, sizeof (int));
int* p3 = (int*)realloc(p2, sizeof(int)*10);
// 这里需要free(p2)吗?
free(p3);
}
对于区别,直接看我之前的博客
对于另一个问题,我们知道realloc扩完容之后,原地扩容则p2和p3是一样,如果是异地扩容realloc会把p2释放掉
三、C 内存管理方式
C语言内存管理方式在C 中可以继续使用,但有些地方就无能为力而且使用起来比较麻烦,因此C 又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。
1.new/delete操作内置类型
代码语言:javascript复制int main()
{
//内置类型
//相比于malloc/free,除了用法没有其他区别
//动态申请一个int类型的空间
int* p1 = new int;
delete p1;
//动态申请一个int类型的空间并初始化为0
int* p2 = new int(0);
delete p2;
//动态申请10个int类型的空间
int* p3 = new int[10];
delete[] p3;
//动态申请10个int类型的空间,并初始化
int* p4 = new int[10]{ 1,2,3,4 };
delete[] p4;
return 0;
}
注:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[]
同时,malloc失败会返回一个空指针
而new失败会抛出异常:
代码语言:javascript复制void Test()
{
while (1)
{
//new失败,抛出异常——不需要检查返回值
char* p1 = new char[1024 * 1024 * 1024];
cout << (void*)p1 << endl;
}
}
int main()
{
try
{
Test();
}
catch (exception& e)
{
cout << e.what() << endl;
}
return 0;
}
真正的区别在于操作自定义类型