【C++那些事儿】C++内存管理 | new和delete的底层原理 | operator new与operator delete函数 | 你听说过定位new吗?| 内存泄露
📷
江池俊:个人主页
VPS购买请点击我 🔥 个人专栏:✅C++那些事儿 ✅Linux技术宝典
🌅 此去关山万里,定不负云起之望
文章目录
- 1. C/C++内存分布
- 2. C语言中动态内存管理方式:malloc/calloc/realloc/free
- 【面试题】
- malloc的实现原理?
- 3. C++内存管理方式
- 3.1 new/delete操作内置类型
- 3.2 new和delete操作自定义类型
- 4. operator new与operator delete函数
- 4.1 operator new与operator delete函数(重点)
- 5. new和delete的实现原理
- 5.1 内置类型
- 5.2 自定义类型
- 6. 定位new表达式(placement-new)
- 内存池简介
- 7. 常见面试题
- 7.1 malloc/free和new/delete的区别
- 7.2 内存泄漏
- 7.2.1 什么是内存泄漏,内存泄漏的危害
- 7.2.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. 选择题: 选项 : A.栈 B.堆 C.数据段(静态区) D.代码段(常量区) globalVar在哪里?__C__ staticGlobalVar在哪里?__C__ staticVar在哪里?__C__ localVar在哪里?__A__ num1 在哪里?__A__ char2在哪里?__A__ * char2在哪里?_A__ pChar3在哪里?__A__ * pChar3在哪里?__D__ ptr1在哪里?__A__ * ptr1在哪里?__B__ 2. 填空题: sizeof(num1) = __40__; sizeof(char2) = __5__; strlen(char2) = __4__; sizeof(pChar3) = __4 or 8__; strlen(pChar3) = __4__; sizeof(ptr1) = __4 or 8__; 3. sizeof 和 strlen 区别? sizeof 是运算符,它用于获取类型或对象在内存中的大小, 其操作数可以是一个类型、一个对象或一个类型的表达式。 strlen 是一个函数,它用于获取字符串(即以空字符 '\0' 结尾的字符数组)的长度。 它返回的是字符串中字符的个数,不包括结尾的空字符。
【说明】
- 栈又叫堆栈 - - 非静态局部变量/函数参数/返回值 等等,栈是向下增长的。
- 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。
- 堆用于程序运行时动态内存分配,堆是可以上增长的。
- 数据段 - - 存储 全局数据 和 静态数据。
- 代码段 - -可执行的代码/只读常量。
2. C语言中动态内存管理方式:malloc/calloc/realloc/free
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); }
-
malloc/calloc/realloc的区别是什么?
malloc 主要是在堆上申请一块连续的内存空间,calloc 相对于 malloc 来说还会对申请的空间初始化为 0,realloc 则是对已经申请的空间进行扩容操作,分为原地扩容和异地扩容两种情况。
-
这里需要free(p2)吗?
不需要,因为如果 realloc 是原地扩容的话,那么p3指向的空间就是p2指向的空间,如果是异地扩容的话,p2在扩容时就会被释放。
【面试题】
malloc的实现原理?
glibc中malloc实现原理
malloc的实现原理涉及操作系统的内存管理,并且通常在不同的操作系统和平台上有所不同。但是,一般来说,它的工作原理大致如下:
- 查找空闲内存块:当malloc被调用时,它会首先查找一个足够大的空闲内存块来满足请求。这个查找过程通常涉及一个数据结构(如链表或树),该数据结构记录了系统中所有可用的内存块。
- 分割空闲内存块:如果找到了一个足够大的空闲内存块,malloc会将其分割成两部分:一部分用于满足当前的内存请求,另一部分(如果有的话)作为新的空闲内存块保留。
- 更新内存管理数据结构:malloc会更新其内部的数据结构,以反映新的内存分配情况。这可能包括添加新的空闲内存块,更新已分配内存块的信息,或删除不再需要的空闲内存块。
- 返回内存地址:最后,malloc返回指向新分配的内存块的指针。这个指针可以被程序用来存储数据。
3. C++内存管理方式
C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。
3.1 new/delete操作内置类型
void Test() { // 动态申请一个int类型的空间 int* ptr4 = new int; // 动态申请一个int类型的空间并初始化为10 int* ptr5 = new int(10); // 动态申请10个int类型的空间 int* ptr6 = new int[10]; delete ptr4; delete ptr5; delete[] ptr6; }
注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[],注意:匹配起来使用。
3.2 new和delete操作自定义类型
class A { public: A(int a = 0) : _a(a) { cout cout // new/delete 和 malloc/free最大区别是: // new/delete对于【自定义类型】除了开空间还会调用构造函数和析构函数 A* p1 = (A*)malloc(sizeof(A)); A* p2 = new A(1); free(p1); delete p2; // 内置类型是几乎是一样的 int* p3 = (int*)malloc(sizeof(int)); int* p4 = new int; free(p3); delete p4; A* p5 = (A*)malloc(sizeof(A) * 10); A* p6 = new A[10]; free(p5); delete[] p6; return 0; } // try to allocate size bytes void* p; while ((p = malloc(size)) == 0) if (_callnewh(size) == 0) { // report no memory // 如果申请内存失败了,这里会抛出bad_alloc 类型异常 static const std::bad_alloc nomem; _RAISE(nomem); } return (p); } /* operator delete: 该函数最终是通过free来释放空间的 */ void operator delete(void* pUserData) { _CrtMemBlockHeader* pHead; RTCCALLBACK(_RTC_Free_hook, (pUserData, 0)); if (pUserData == NULL) return; _mlock(_HEAP_LOCK); /* block other threads */ __TRY /* get a pointer to memory block header */ pHead = pHdr(pUserData); /* verify block type */ _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead-nBlockUse)); _free_dbg(pUserData, pHead-nBlockUse); __FINALLY _munlock(_HEAP_LOCK); /* release other threads */ __END_TRY_FINALLY return; } /* free的实现 */ #define free(p) _free_dbg(p, _NORMAL_BLOCK) public: A(int a = 0) : _a(a) { cout cout // p1现在指向的只不过是与A对象相同大小的一段空间,还不能算是一个对象,因为构造函数没有执行 A* p1 = (A*)malloc(sizeof(A)); new(p1)A; // 注意:如果A类的构造函数有参数时,此处需要传参 p1-~A(); free(p1); A* p2 = (A*)operator new(sizeof(A)); new(p2)A(10); p2-~A(); operator delete(p2); return 0; } // 1.内存申请了忘记释放 int* p1 = (int*)malloc(sizeof(int)); int* p2 = new int; // 2.异常安全问题 int* p3 = new int[10]; Func(); // 这里Func函数抛异常导致 delete[] p3未执行,p3没被释放. delete[] p3; }
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。