【C++】深入解析C/C++内存管理:new与delete的使用及原理(二)

简介: 【C++】深入解析C/C++内存管理:new与delete的使用及原理

【C++】深入解析C/C++内存管理:new与delete的使用及原理(一)https://developer.aliyun.com/article/1617320


第一点:

int* p0 = (int*)malloc(sizeof(int));
  int* p1 = new int;

第二点:

int* p2 = new int[10];
  int* p3 = new int(10);
  int* p4 = new int[10]{ 1,2,3 };

第三点

struct ListNode
{
  ListNode* _next;
  int _val;
  ListNode(int val)
    :_val(val)
    ,_next(nullptr)
  {}
};
//创建不带哨兵位,同时如果是插入数据,new ListNode(3)即可
ListNode* CreateList(int n)
{
  ListNode head(-1);
  
  ListNode* tail = &head;
  int val;
  
  printf("请依次输入%d个节点的值:>", n);
  for (size_t i = 0; i < n; i++)
  {
    cin >> val;
    tail->_next = new ListNode(val);
    tail = tail->_next;
  }
  return head._next;
}

第四点:

void func()
{
  int n = 1;
  while (1)
  {
    int* p = new int[1024 * 1024*100];
    cout <<n<<"->"<< p << endl;
    ++n;
  }
}
int main()   
{
   try
  {
    func();
  }
  catch (const exception& e)
  {
    cout << e.what() << endl;
  }
    return 0;
}

这里try和catch就是捕捉异常,这一点到后面有涉及。以上种种都是new的优点,所以我们不推荐再使用malloc/free系列。

四、 new和delete原理及其两个全局函数的实现(operator new/operator delerte)

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

int* p1 = (int*)operator new(10 * 4);
  //int* p1=new int(10*4)
  operator delete(p1);
  //delete(p1)

从代码中可以看出来,new/delete和operator new/operator delete效果上是相同的。那么直接使用new/delete就行,operator new/operator delete对于我们来说是没用的,但是有这个东西说明在系统中有它们的一席之地的。

/*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间
失败,尝试执行空 间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。
*/
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
    // try to allocate size bytes
    void *p;
    while ((p = malloc(size)) == 0)
    //通过上述两个全局函数的实现知道,operator new 实际也是通过malloc来申请空间,如果
    //malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施
    //就继续申请,否则就抛异常。operator delete 最终是通过free来释放空间的。
    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)

可以通过上述两个全局函数的实现,可以知道,operator new实际是通过malloc来申请空间,如果malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施;如果用户提供该措施就继续申请,否则就抛异常。operator delete最终是通过free来释放空间的。

内置类型:

如果申请的是内置类型的空间,new/malloc与delete/free基本类似,不同的地方是new在申请空间失败时会抛异常,malloc会返回NULL

自定义类型:

new的原理:

  1. 调用operator new函数申请空间
  2. 在申请的空间上执行构造函数,完成对象的构造

delete的原理:

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

new T[N]的原理:

  1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请
  2. 在申请的空间上执行N次构造函数

delete[]的原理:

  1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
  2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间

通过汇编,深入立即其中

对于自定义类型转换指令只有两个核心动作调用全局函数及其构造或析构,而内置类型只有调用全局函数。

对此可得:

  • operator new是对malloc的封装,如果失败抛异常,实现new
  • operator newp[]封装operator new,最终还是malloc
  • operator delete对free的封装
  • operator delete[]封装operator delete

同时这里需要注意调用顺序上的问题


【C++】深入解析C/C++内存管理:new与delete的使用及原理(三)https://developer.aliyun.com/article/1617323

相关文章
|
5月前
|
Web App开发 缓存 监控
内存溢出与内存泄漏:解析与解决方案
本文深入解析内存溢出与内存泄漏的区别及成因,结合Java代码示例展示典型问题场景,剖析静态集合滥用、资源未释放等常见原因,并提供使用分析工具、优化内存配置、分批处理数据等实用解决方案,助力提升程序稳定性与性能。
1375 2
|
11月前
|
机器学习/深度学习 存储 算法
NoProp:无需反向传播,基于去噪原理的非全局梯度传播神经网络训练,可大幅降低内存消耗
反向传播算法虽是深度学习基石,但面临内存消耗大和并行扩展受限的问题。近期,牛津大学等机构提出NoProp方法,通过扩散模型概念,将训练重塑为分层去噪任务,无需全局前向或反向传播。NoProp包含三种变体(DT、CT、FM),具备低内存占用与高效训练优势,在CIFAR-10等数据集上达到与传统方法相当的性能。其层间解耦特性支持分布式并行训练,为无梯度深度学习提供了新方向。
564 1
NoProp:无需反向传播,基于去噪原理的非全局梯度传播神经网络训练,可大幅降低内存消耗
|
5月前
|
弹性计算 定位技术 数据中心
阿里云服务器配置选择方法:付费类型、地域及CPU内存配置全解析
阿里云服务器怎么选?2025最新指南:就近选择地域,降低延迟;长期使用选包年包月,短期灵活选按量付费;企业选2核4G5M仅199元/年,个人选2核2G3M低至99元/年,高性价比爆款推荐,轻松上云。
513 11
|
10月前
|
存储 缓存 Java
【高薪程序员必看】万字长文拆解Java并发编程!(5):深入理解JMM:Java内存模型的三大特性与volatile底层原理
JMM,Java Memory Model,Java内存模型,定义了主内存,工作内存,确保Java在不同平台上的正确运行主内存Main Memory:所有线程共享的内存区域,所有的变量都存储在主存中工作内存Working Memory:每个线程拥有自己的工作内存,用于保存变量的副本.线程执行过程中先将主内存中的变量读到工作内存中,对变量进行操作之后再将变量写入主内存,jvm概念说明主内存所有线程共享的内存区域,存储原始变量(堆内存中的对象实例和静态变量)工作内存。
300 0
|
6月前
|
存储 大数据 Unix
Python生成器 vs 迭代器:从内存到代码的深度解析
在Python中,处理大数据或无限序列时,迭代器与生成器可避免内存溢出。迭代器通过`__iter__`和`__next__`手动实现,控制灵活;生成器用`yield`自动实现,代码简洁、内存高效。生成器适合大文件读取、惰性计算等场景,是性能优化的关键工具。
334 2
|
7月前
|
弹性计算 前端开发 NoSQL
2025最新阿里云服务器配置选择攻略:CPU、内存、带宽与系统盘全解析
本文详解2025年阿里云服务器ECS配置选择策略,涵盖CPU、内存、带宽与系统盘推荐,助你根据业务需求精准选型,提升性能与性价比。
|
8月前
|
安全 C语言 C++
比较C++的内存分配与管理方式new/delete与C语言中的malloc/realloc/calloc/free。
在实用性方面,C++的内存管理方式提供了面向对象的特性,它是处理构造和析构、需要类型安全和异常处理的首选方案。而C语言的内存管理函数适用于简单的内存分配,例如分配原始内存块或复杂性较低的数据结构,没有构造和析构的要求。当从C迁移到C++,或在C++中使用C代码时,了解两种内存管理方式的差异非常重要。
273 26
|
8月前
|
存储 弹性计算 固态存储
阿里云服务器配置费用整理,支持一万人CPU内存、公网带宽和存储IO性能全解析
要支撑1万人在线流量,需选择阿里云企业级ECS服务器,如通用型g系列、高主频型hf系列或通用算力型u1实例,配置如16核64G及以上,搭配高带宽与SSD/ESSD云盘,费用约数千元每月。
1008 0
|
9月前
|
存储 缓存 数据挖掘
阿里云服务器实例选购指南:经济型、通用算力型、计算型、通用型、内存型性能与适用场景解析
当我们在通过阿里云的活动页面挑选云服务器时,相同配置的云服务器通常会有多种不同的实例供我们选择,并且它们之间的价格差异较为明显。这是因为不同实例规格所采用的处理器存在差异,其底层架构也各不相同,比如常见的X86计算架构和Arm计算架构。正因如此,不同实例的云服务器在性能表现以及适用场景方面都各有特点。为了帮助大家在众多实例中做出更合适的选择,本文将针对阿里云服务器的经济型、通用算力型、计算型、通用型和内存型实例,介绍它们的性能特性以及对应的使用场景,以供大家参考和选择。

推荐镜像

更多
  • DNS