您现在的位置是:首页 >技术交流 >【C++】C/C++内存管理网站首页技术交流
【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 new
和operator 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 new
和operator delete
.那是因为它们还有一个作用:抛异常
面向对象的语言处理失败,不喜欢使用返回值,而是更建议使用抛异常
比如:c语言函数出错,一般会返回-1等,然后根据返回值来判断错误是什么,但c++更喜欢直接告诉我们哪里错了,为什么错了,即直接抛出异常。
下面我们打开反汇编看看是否如上所说:可见使用new时,调用了operator new 和 A的构造函数
四、定位new表达式
定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象
使用方式:new + (空间地址) + 构造函数
这种用法主要是为了配合内存池使用:
内存池(Memory Pool)是一种为程序分配内存的技术,在程序开始时一次性分配一大块内存,然后程序在需要内存时就从这个内存池中分配内存,而不是每次都向操作系统请求分配内存。这种方法可以提高内存分配和释放的效率。内存池通常用于管理动态内存分配,例如在高性能计算或实时系统中,以避免频繁的内存分配操作导致的性能下降或内存碎片化问题。
五、new/delete和malloc/free的区别 - 重点
malloc/free和new/delete的共同点是:都是从堆上申请空间,并且需要用户手动释放。不同的地
方是:
- malloc和free是函数,new和delete是操作符
- malloc申请的空间不会初始化,new可以初始化
- malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可,
如果是多个对象,[]中指定对象个数即可 - malloc的返回值为void*, 在使用时必须强制类型转换,new不需要,因为new后跟的是空间的类型
- malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需
要捕获异常 - 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new
在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成
空间中资源的清理