您现在的位置是:首页 >技术交流 >【C++】C/C++内存管理网站首页技术交流

【C++】C/C++内存管理

ProcedureStone 2024-06-26 14:23:52
简介【C++】C/C++内存管理


前言


一、c/c++的内存分布

c和c++的内存分布如下:
在这里插入图片描述

看下面的代码,明确每个变量存储在哪一块空间?
在这里插入图片描述

选择题:
选项: A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)
globalVar在哪里?____ staticGlobalVar在哪里?____
staticVar在哪里?____ localVar在哪里?____
num1 在哪里?____

答案:C C C A A A

char2在哪里?____ *char2在哪里?___
pChar3在哪里?____ *pChar3在哪里?____
ptr1在哪里?____ *ptr1在哪里?____

答案:A A A D A B


二、c++的内存管理

C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。

在这里插入图片描述
相比较c,c++的new可以进行初始化,如下:
在这里插入图片描述


但new/delete存在的意义,仅仅是写起来更方便吗?不,new/delete还有一个很重要的特性,为自定义类型开空间时,会调用构造函数/析构函数。
在这里插入图片描述

正因new/delete具有这样的性质,所以new和delete,malloc和free最好要匹配使用,不能随意混搭。
在这里插入图片描述


三、new/delete的底层

首先我们要了解两个函数operator newoperator delete
你可能认为这是new,delete是运算符重载函数,属于并列关系,但它们真正的作用是服务于new/delete,属于从属关系。哪它们的功能是什么?
我们将new和delete的功能拆成以下几个部分:
在这里插入图片描述
可见operator new和operator delete主要为了开辟/回收空间。
它们的实现如下:

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)
     {
         static const std::bad_alloc nomem;
         _RAISE(nomem);
     }
return (p);
}
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)

其中,它们开/回收空间的方式是通过使用malloc和free。
哪为什么不直接让new/delete使用malloc/free,而是在new/delete下面加了一层operator newoperator delete.那是因为它们还有一个作用:抛异常

面向对象的语言处理失败,不喜欢使用返回值,而是更建议使用抛异常
比如:c语言函数出错,一般会返回-1等,然后根据返回值来判断错误是什么,但c++更喜欢直接告诉我们哪里错了,为什么错了,即直接抛出异常。


下面我们打开反汇编看看是否如上所说:可见使用new时,调用了operator new 和 A的构造函数
在这里插入图片描述


四、定位new表达式

定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象

在这里插入图片描述

使用方式:new + (空间地址) + 构造函数

这种用法主要是为了配合内存池使用:

内存池(Memory Pool)是一种为程序分配内存的技术,在程序开始时一次性分配一大块内存,然后程序在需要内存时就从这个内存池中分配内存,而不是每次都向操作系统请求分配内存。这种方法可以提高内存分配和释放的效率。内存池通常用于管理动态内存分配,例如在高性能计算或实时系统中,以避免频繁的内存分配操作导致的性能下降或内存碎片化问题。


五、new/delete和malloc/free的区别 - 重点

malloc/free和new/delete的共同点是:都是从堆上申请空间,并且需要用户手动释放。不同的地
方是:

  1. malloc和free是函数,new和delete是操作符
  2. malloc申请的空间不会初始化,new可以初始化
  3. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可,
    如果是多个对象,[]中指定对象个数即可
  4. malloc的返回值为void*, 在使用时必须强制类型转换,new不需要,因为new后跟的是空间的类型
  5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需
    要捕获异常
  6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new
    在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成
    空间中资源的清理
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。