new、delete和malloc、free

news2024/11/15 19:40:59

C++内存

图片来源阿秀的学习笔记
在这里插入图片描述

  • 栈:函数内局部变量可以存储在栈区,函数执行结束自动释放。栈区内区分配运算内置于处理器指令集中
  • 堆:new分配的内存块,由应用程序控制
  • 自由存储区:和堆比较像,但是不等价
  • 全局数据区、静态存储区:全局变量和静态变量被分配到同一块内存中。C++中,该区定义的变量若是没有初始化,则会被自动初始化。
  • 常量存储区:存放常量,不允许修改
  • 代码区:存放函数体的二进制代码

malloc和calloc和realloc

malloc

标准C库中,使用malloc和free函数分配释放内存,底层是由brk,mmap,munmap实现。只进行空间申请不初始化

brk是将数据段的最高地址指针向高地址推,mmap是在进程的虚拟地址中(堆和栈中间)找一块空闲的虚拟内存
malloc小于12K的内存使用brk分配,大于128K,使用mmap分配(在堆和栈中间找一块内存分配,brk要等高地址内存释放才能释放,而mmap分配的内存可以单独释放)最高地址空间空闲内存超过128K的时候,执行内存紧缩操作。

malloc从堆上面申请内存。操作系统中有一个记录空闲内存地址的链表,操作系统收到程序的申请时,就会遍历这个链表,找到第一个大于申请空间的堆结点,将该结点从链表中删除,将这个结点的空间分配给程序。

malloc分配内存失败原因
1、内存不足
2、前面程序中出现了内存的越界访问,导致malloc()分配函数所涉及的一些信息被破坏

  • 当malloc分配内存不足时,通常有三种方式处理。第一种是判断指针是否为NULL,如果是则马上用return语句终止本函数。第二种是判断指针是否为NULL,如果是则马上用exit(1)终止整个程序的运行。第三种是为new和malloc设置异常处理函数。
  • 如果程序出现了内存的越界访问,那么就会导致malloc()分配函数所涉及的一些信息被破坏。下次再使用malloc()函数申请内存就会失败,返回空指针NULL(0)。
    高质量的c/c++编程有关malloc分配内存不足的问题
    malloc函数分配内存失败的原因及解决方法
void* malloc(unsigned int num_size);//返回类型为void*
int *p = malloc(20*sizeof(int));申请20int类型的空间;

calloc

函数原型void* calloc(size_t number, size_t size);参数number为要申请的个数;size为每一个数据的大小,返回值是void*,通常要强转为我们需要申请空间的类型,开辟成功回返回空间首地址,失败会返回NULL,但是申请成功会对空间进行初始化,且初始为0。

realloc

函数原型void*realloc(void * mem_address, unsigned int newsize);

  • 参数address为要扩展调整的空间首地址
  • 参数newsize为调整为多少字节的空间
  • 返回值是void*,通常要强转为我们需要申请空间的类型,开辟成功回返回空间首地址,失败会返回NULL,但是申请成功后并不进行初始化,每个数据都是随机值

注意的是,之前申请过的空间再用realloc来扩展的话不用释放,只要释放扩展后的空间即可.

1、如果第一个参数是nullptr/NULL,就相当于malloc
2、调整空间大小:如果原来的内存大小后面还有足够的内存空闲用来分配,那么就在原来的后面分配空间;如果没有足够空间了,那么从堆中另外找一块内存,将原来的内存中的内容复制到新的内存中,所以最好把realloc返回的值重新赋值给p,释放原来的空间(注意二次释放的问题)

free

  • 被free回收的内存不是立即返回给操作系统的,首先被ptmalloc使用双链表保存起来,用户下一次申请内存的时候,会从这些内存中寻找合适的返回,避免频繁的系统调用,占用过多的系统资源。
    ptmalloc 也会尝试对小块内存进行合并,避免过多的内存碎片。

new和delete

首先new和delete都是运算符,不是库函数,不需要单独添加头文件;然后new和delete是通过malloc和free来释放空间的;new申请空间失败的时候会抛出异常,malloc申请空间失败的时候会返回NULL。

new 实现原理

  1. 调用名为operator new的标准库函数,分配足够大的原始为类型化的内存,以保存指定类型的一个对象。
  2. 运行该类型的一个构造函数,指定初始化构造对象
  3. 返回指向新分配并构造后的对象的指针。

operator new ()全局函数原型:

/*
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)
 if (_callnewh(size) == 0)
 {
 // report no memory
 // 如果申请内存失败了,这里会抛出bad_alloc 类型异常
 static const std::bad_alloc nomem;
 _RAISE(nomem);
 }
 return (p);
}

动态数组管理new一个数组的时候,[]中必须是一个整数,但是不一定是常量整数,普通数组必须是一个常量整数
new动态数组返回的并不是数组类型,而是一个元素类型的指针

delete 实现原理

  1. 对指针指向的对象运行适当的析构函数
  2. 通过调用明为operator delete的标准库函数释放该对象所用的内存
/*
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)

new和malloc的区别

  1. malloc和free是标准库函数支持覆盖(所以需要库文件支持),new和delete是运算符,支持重载。
  2. malloc和free仅仅分配和回收空间,不具备调用构造函数和析构函数功能,分配空间存储类的对象存在风险。
  3. malloc和free返回的是void指针,需要通过强制类型转换将void转换成我们需要的类型;new和delete返回的是具体类型指针,类型严格与对象匹配。所以new是类型安全的
  4. malloc需要手工计算出所需要的内存的大小,而new是编译器根据信息自行计算所需内存大小的。
  5. new申请空间失败的时候会抛出异常,malloc申请空间失败的时候会返回NULL。

allocator

allocator允许我们将分配和初始化分离,使用allocato 通常会提供更好的性能和更灵活的内存管理能力。
new有一些灵活性上的局限性-将内存分配和对象构造组合在一起。当我们分配单个对象,一般希望内存分配和对象初始化组合在一起;但是当分配一大块内存的时候,我们可能更喜欢在这块内存上按需构造对象也就是将内存分配和对象构造分离。我们分配大块内存,但是在真正需要时才真正执行对象的创建操作。因为一般情况下将内存分配和对象构造组合在一起会有一些不必要的开销

头文件

#include<memory>

函数

在这里插入图片描述

  • allocate分配的内存是未构造的,我们按需在这个内存中构造对象。
  • construct成员函数接受一个指针和零个或者多个额外参数,在给定位置构造一个元素。(额外参数是用来初始化构造的对象,类似make_shared参数,这些额外参数必须是与构造的对象的类型相匹配的合法的初始化器)使用未构造的内存,其行为未定义
  • 我们用完对象之后,必须对每个构造的元素调用destroy来销毁,destroy接受一个指针,对执行的对象执行析构函数。
  • deallocate释放内存,传递给deallocate的指针不能为空,必须指向由allocate分配的内存。而且传递给deallocate的大小参数应该与调用allocate分配内存时提供的大小参数一致。

new[]和delete[]

new[]

new简单类型直接调用operator new分配内存,对于复杂结构,先调用operator new分配内存,然后在分配的内存上调用构造函数;对于简单类型,new[]计算好大小之后调用operator new,对于复杂数据结构,先调用operator new[]分配内存,然后在p的前四个字节写入数组大小n,然后调用n次构造函数。针对复杂类型,new[]额外存储数组大小

delete[]

  • delete简单数据类型只是调用free函数,复杂数据类型先调用析构函数再调用operator delete;针对简单类型,delete和delete[]等同
  • 为什么new[]要与delete[]对应?因为假设p指向new[]分配的内存,是用了四个字节来存储数组大小,实际分配内存地址为[p-4]系统也是记录这个地址,delete[]实际释放的也是p-4指向的内存,而delete会直接释放p指向的内存这个内存没有被系统记录,所以会崩溃。

malloc和new分配内存的时候,系统都会将分配的内存空间首地址的前四个字节中存储所分配的内存大小值

  • delete[]时,数组中的元素按照逆序的顺序进行销毁
  • delete[]的时候,可以取出那4个字节空间里面的数,这个数记录了数组大小,然后就知道要调用析构函数多少次了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/442880.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

406. 根据身高重建队列

假设有打乱顺序的一群人站成一个队列&#xff0c;数组 people 表示队列中一些人的属性&#xff08;不一定按顺序&#xff09;。每个 people[i] [hi, ki] 表示第 i 个人的身高为 hi &#xff0c;前面 正好 有 ki 个身高大于或等于 hi 的人。 请你重新构造并返回输入数组 peopl…

生成与指定数组具有相同形状的全1数组np.ones_like()方法

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 生成与指定数组A形状相同的全1数组 np.ones_like() 选择题 关于以下代码说法错误的一项是? import numpy as np a np.array([[0,1],[2,3]]) print("【显示】a\n",a) print(&qu…

九龙证券|293份一季报预告逾七成预喜 机械设备等赛道业绩亮眼

2023年一季报预告正在连续出炉。Choice数据显现&#xff0c;截至4月17日21时&#xff0c;已有293家上市公司发布2023年一季报预告&#xff0c;按估计完成归母净利润同比变化幅度上限来看&#xff0c;其间有219家公司成绩预喜&#xff0c;占比约74.74%。分职业来看&#xff0c;机…

List

1.基本概念 功能: 将数据进行链式存储 链表(list) 是一种物理存储单元上非连续的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接实现的 链表的组成: 链表由一系列结点组成 结点的组成: 一个是存储数据元素的数据域&#xff0c;另一个是存储下一个结点地址的…

18.生命周期

目录 1 开启生命周期 2 创建前 beforeCreate() 3 创建后 created() 4 渲染前 beforeMount() 5 渲染后 mounted 6 更新渲染前 beforeUpdate() 7 更新渲染后 updated() 8 移除前 beforeUnmount() 9 移除后 unmounted() 生命周期是指 一个组件从创建->运行-&…

linux安装和使用jekins

Jenkins详细安装配置部署--超详细_jenkins安装部署_宝贝富贵猪的博客-CSDN博客 1.安装JDK 2.获取安装包 下载页面&#xff1a;https://jenkins.io/zh/download/ 或者Index of /jenkins/redhat/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 3.安装Jenkins sud…

深入理解Android布局:ConstraintLayout和RecyclerView的使用

深入理解Android布局&#xff1a;ConstraintLayout和RecyclerView的使用 I. 引言 介绍Android中布局的重要性 提出使用ConstraintLayout和RecyclerView布局的目的和意义 II. ConstraintLayout的使用 介绍ConstraintLayout的基本概念和特点 详细介绍ConstraintLayout的各种属性…

Spring Cloud微服务架构组件【Java培训】

SpringCloud是一系列框架的有序集合&#xff0c;为开发人员构建微服务架构提供了完整的解决方案。Spring Cloud根据分布式服务协调治理的需求成立了许多子项目&#xff0c;每个项目通过特定的组件去实现&#xff0c;下面我们讲解一下Spring Cloud 包含的常用组件以及模块。 (1…

【工业智能】需要了解的知识

【工业智能】需要了解的知识 算法数据预测模型决策协同模型优化控制异常诊断 图像目标检测语义分割关键点检测图像匹配3D抓取度量学习异常检测6D姿态估计 工业自动化、物联网通信IOT工业自动化边缘计算 写在前面&#xff1a; 本文仅为自己记录&#xff0c;不具有指导意义。 算法…

软文推广:真实有效提升软文排名与收录的三大方法!

软文是一种具有良好传播效果的文体&#xff0c;可以通过在搜索引擎中排名靠前的方式&#xff0c;为品牌或企业带来更多曝光。但是&#xff0c;如何让软文在搜索引擎中得到更好的收录和排名呢&#xff1f;在本文中&#xff0c;我们将讨论如何提升软文的收录和排名&#xff0c;以…

【DNS域名解析服务】

目录 一、DNS系统的作用DNS的介绍1.1、通用的顶级域名 二、DNS域名解析&#xff08;面试题&#xff09;三、DNS查询方式递归查询迭代查询 四、构建DNS域名服务器步骤4.1、安装bind软件包4.2、修改配置文件4.3、域名的配置修改区域配置文件&#xff0c;添加正向区域配置 4.4、覆…

Canokey Pigeon的初级玩法

Canokey Pigeon的初级玩法 前言开箱使用控制台新版旧版 初步设置FIDO2 PIN更改重置 坑&#xff08;或者说不满意的地方&#xff09;玩法FIDO2/U2FOpenPGPPIVNDEFOATH 参考 本文转载于我的博客Canokey Pigeon的初级玩法 Canokey Pigeon今天终于到货了 {% note warning flat %} …

【C++缺省参数、函数重载详解】

目录 一、缺省参数1.1缺省参数的定义1.2缺省参数的分类1.3缺省参数使用时的注意事项 二、函数重载2.1函数重载的概念2.2为什么要有函数重载2.3 C支持函数重载的原理 一、缺省参数 1.1缺省参数的定义 缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时&a…

搭建B2B2C多用户国际版商城系统,快速为外贸企业开拓新市场

企业市场竞争激烈&#xff0c;不只体现在国内&#xff0c;甚至全球&#xff0c;电商行业发展迅速&#xff0c;各企业各行业甚至进出口都竞争相当激烈。要想在这种告诉竞争中脱颖而出&#xff0c;开拓新市场&#xff0c;带来新盈利与新契机是必不可少的。易族智汇Javashop助力企…

nmap学习笔记

一、环境准备 Windows10主机Kali虚拟机&#xff08;使用nmap的地方&#xff09;metasploitable虚拟机为以上三个操作系统配置静态IP。 Windows主机的IP&#xff1a;192.168.80.3Kali的IP&#xff1a;192.168.80.2metasploitable的IP&#xff1a;192.168.80.4 具体配置方法请参…

STM32-窗口看门狗WWDG实验

窗口看门狗本质上是一个能产生系统复位信号和提前唤醒中断的定时器。它通常被用来监测&#xff0c;由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。除非递减计数器的值在T6位变成0前被刷新&#xff0c;否则看门狗电路在达到预置的时间周期时…

代码随想录二刷-队列及其应用题目(JS)【重要】

239.滑动窗口最大值 题目 给定一个数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回滑动窗口中的最大值。 进阶&#xff1a; 你能在线性时间复杂度内解决此题吗…

Thinkpad-t470电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。&#xff08;下载请直接百度黑果魏叔&#xff09; 硬件型号驱动情况 主板Thinkpad-t470 处理器Intel Core i7-6600U 2.6GHz / 3.4Ghz Turbo已驱动 内存16GB DDR4 2666Mhz (SK Hynix)已驱动 硬盘Intel SSD Pro 7600P 51…

与Linux的文件权限有关的知识

在Linux系统中&#xff0c;每个文件都有一个所有者和一个用户组。此外&#xff0c;系统还定义了一个“其他人”分类。 文件的所有者通常是创建该文件的用户&#xff0c;而用户组则是在创建该文件时指定的。如果没有指定&#xff0c;则默认为创建用户的主用户组。用户组可以在文…

核心业务1:账户绑定业务

核心业务1:账户绑定业务 1.业务流程图 2.账户绑定数据库设计 3.账户绑定业务流程 4.代码逻辑 5.代码逻辑细节 核心业务1:账户绑定业务 1.业务流程图 ①用户绑定数据到商户平台(已