C++ 内存管理原理分析 您所在的位置:网站首页 c内存分布图 C++ 内存管理原理分析

C++ 内存管理原理分析

2023-03-13 01:02| 来源: 网络整理| 查看: 265

目录1.C/C++中程序内存分布1.1 内存分布图1.2 小试牛刀2.C语言部分的动态内存管理方式3.C++内存管理方式3.1new/delete操作内置类型3.2 new/delete操作自定义类型4.new和delete底层实现原理(important!!!)4.1operator new/operator delete4.2new和delete的实现原理内置类型自定义类型5.相关面经5.1malloc/free与new/delete的区别5.2什么是内存泄漏?5.3内存泄漏的危害5.4如何预防内存泄漏(先了解一下,后续作者再详细介绍)

1.C/C++中程序内存分布

C/C++中程序内存区域大致划分为:内核空间(这部分用户不能读写)、栈、内存映射段、堆、数据段(存储全局数据、静态数据)、代码段(存储可执行代码、只读常量,又称常量区)。

1.1 内存分布图

1.2 小试牛刀

接下来看下如下代码,思考下每一个变量分别在哪个内存区域?

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"; char *pchar3 = "abcd";//有的编译器会报错,需要用const char 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(ptr2); }

上述代码段对应变量区域划分如下:

2.C语言部分的动态内存管理方式

再来回顾一下之前C语言部分的动态内存管理方式:malloc / calloc/ realloc和free

带着两个问题阅读下述程序段:

1.malloc / calloc/ realloc的区别是什么?

2.最后需要free(p2)吗?

void Test() { int* p1 = (int*)malloc(sizeof(int)); free(p1); int* p2 = (int*)calloc(4, sizeof(int)); int* p3 = (int*)realloc(p2, sizeof(int) * 10); free(p3); }

答:

1.calloc相当于malloc+memset(0),即开空间+初始化。

2.realloc是对malloc/calloc的空间进行扩容,扩容之下又涉及到了咱们前面所讲的原地扩容和异地扩容俩种情景:原地扩容p2和p3是一样的,也有可能是异地扩容,那么p2指向的空间已经被释放了,所以两种情况下我们都可以不需要处理p2。

3.C++内存管理方式

总之就是C语言那套内存管理方式相对麻烦,所以C++提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理.

3.1new/delete操作内置类型

1.开辟单个元素

开辟单个元素基本语法: type * ptr = new type(content); ,可以理解成动态申请一个type类型的空间并将其中内容初始化为content,当然,你也可以选择不初始化。

释放空间语法: delete name;

例:

int* a = new int(100); //动态申请一个int类型的空间并初始化为100 delete a;

2.开辟n个type类型的空间

开辟n个type类型基本语法: type* name = new type[n]

删除的基本语法:delete[] name;

例:

int* ptr = new int[100];//动态申请100个int类型的空间 delete[] ptr; //注意哦!一定要匹配哦!不然必崩溃!

3.对于内置类型,malloc/free和new/delete确实没有什么区别,二者的作用完全一样。

例:

int main() { //malloc向内存申请4个整型大小的空间 int* p1 = (int*)malloc(sizeof(int) * 4); //new向内存申请4个整型大小的空间 int* p2 = new int[4]; //free释放掉p1申请的空间 free(p1); p1 = nullptr; //delete释放掉p2申请的空间 delete[] p2; return 0; }

3.2 new/delete操作自定义类型 class Date { public: Date(int year=2021, int month=1, int day=1) { _year = year; _month = month; _day = day; } private: int _year; int _month; int _day; }; int main() { //malloc申请十个Date空间 Date* p1 = (Date*)malloc(sizeof(Date) * 10); free(p1); //new申请十个Date空间 Date* p2 = new Date[10]; delete[] p2; return 0; }

区别:在申请自定义类型空间的时候,new会调用构造函数,delete会调用析构函数,而mallo和free不会哦!

4.new和delete底层实现原理(important!!!)

在讲解他们的底层实现原理之前需要先先介绍一下两个全局函数,分别是operator new 和operator delete.

new和delete是用户进行动态内存申请和释放的操作符,operator new和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过调用operator delete全局函数来释放空间。

4.1operator new/operator delete

operator new封装了 malloc 和失败抛异常俩个部分,

下面是operator new的代码:

void* __CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc) { // 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

下面是operator delete的代码:

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; }

总结:通过观察上述俩个全局函数的实现,不难发现operator new实际也是通过malloc来申请空间,如果malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常,operator delete最终是通过free来释放空间的。

4.2new和delete的实现原理

内置类型

malloc/free与new/delete在处理内置类型时并没有区别,只是malloc申请空间失败时返回空指针,而new申请空间时是抛异常,new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间。

自定义类型

1.new的原理:1.调用operator new函数申请空间。2.在申请空间上执行构造函数,完成对象的初始化。

2.delete的原理:1.在空间上执行析构函数,完成对象中资源的清理工作。2.调用operator delete函数释放空间。

另外new T[N]的原理:调用operator new[]函数,在operator new[]中实际调用N次operator new函数完成N个对象空间的申请,然后在申请的空间上执行N次构造函数。**delete[]的原理:**在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理。然后调用operator delete[]释放空间,实际在operator delete[]中调用N次operator delete来释放空间。

初学者看到“delete调用析构函数,完成对象资源的清理工作,后边又调用operator delete函数释放空间”这部分内容时可能会比较混乱,这里以栈为例子详细说下:

struct Stack { int* _a; int _top; int _capacity; Stack(int capacity = 4) :_a(new int[capacity]) ,_size(0) ,_capacity(capacity) { cout


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有