C / C++内存管理

server/2024/10/22 8:39:21/

内存分布

1. 栈又叫堆栈--非静态局部变量/函数参数/返回值等等,栈是向下增长的。

2. 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共 享内存,做进程间通信,子进程堆区的开辟。

3. 堆用于程序运行时动态内存分配,堆是向上增长的。

4. 数据段--存储全局数据和静态数据。

5. 代码段--可执行的代码/只读常量。

在C和C++中我们的函数内变量都是存在于栈上的,当程序开始执行时,系统会在为函数在栈上开辟一块空间以存放函数产生的数据,栈是向下生长的,每当我们开辟一块栈空间,就有一个指针向下移动。

我们编写程序的时候会用到很多的库函数如iostream,vector,string的函数,在整个程序里面这些都只需要一份而且基本上每个程序或者进程需要的都是同一份,在程序执行或者说进程启动时这一份数据就会存放在内存映射段中,映射段内的数据被整个程序所有的线程所共享。

堆区用于我们动态开辟内存使用的,这里的空间是被我们自己开辟,管理和释放的,若是我们使用完后没有主动去释放这块内存就会导致内存泄漏影响程序的效率。

数据段也叫静态区,这是存放全局数据和静态数据的地方(被static修饰的变量)

代码段也叫常量区,可执行的代码存放位置,也是常量的存放地方(如const修饰的变量,平时直接使用的常量"123456789abcd"这些不会改变的都是放在这个地方),这些只是规定的不会改变,其实只要我们能拿到这个位置的地址,通过地址去访问内存的全部数据都是可以修改的。

在操作系统为程序或者说进程分配内存的时候这个表肯定是会复杂很多,并且有相应的算法对应内存的开辟和使用管理,不过在语言层,它也就只需要考虑上图的分配数据管理方式即可。最上层的内核空间就是映射的操作系统的内存地址的空间每个程序都拥有一份是方便程序(进程)与系统的切换,例如需要调用系统接口的时候。

C语言中管理内存的方式

C语言中4个函数用于动态管理内存:malloc/calloc/realloc/free  这四个函数前两个是动态开辟内存的函数

这里我们分别使用malloc和calloc在堆上创建了一块相同大小的空间,malloc的参数是字节数这里一共8字节,calloc的第一个参数代表我们需要创建的空间要存放几个数据,第二个参数代表每一个数据的大小。这两个都是在堆上动态开辟空间的,差异点就是参数和初始化,calloc是会 将开辟的空间内数据都初始化为0,malloc是不理会的,原来里面的数据是怎么样现在还是怎么样。这两个函数的返回值都是一个void*的指针指向开辟好的内存的首地址,因为这里只负责开辟一块规定大小的内存,至于里面存什么数据怎么使用这块内存函数是不管的,所以我们需要对其进行强转为我们需要的类型再进行使用。

realloc函数是用于动态调整开辟后的内存的

这里我是使用realloc将p所指向的空间从原来的8字节改为12字节,若是p所指向的空间后面是有4个字节大小的话就会直接将空间不动向后阔4个字节,若是后面不存在这么大空间的话就会在堆上的其他地方开辟一个连续的12字节的空间再将原来空间的内容拷贝过去。

用以上三个函数开辟空间或者动态调整空间大小都是有机会失败的,若是失败会返回一个NULL空指针,所以正常使用的话是需要对指针进行判断的。

在堆中开辟了空间后这快空间就完全由我们自己管理的,这里我们开辟的内存在后续没有使用需求的时候是需要我们自己去释放这块空间将这块空间交还给操作系统管理的这就是free函数的作用

将指针传递给函数free就会帮我们将空间交换给系统。

C++中的内存管理

C++是兼容C语言的,上述函数在C++中都可以使用,但是大部分时候使用C语言的内存管理函数会有些麻烦,它就只是单纯的给我开辟一段空间,而且失败了也没有任何提示需要我们自己去判断,所以C++也对其进行了改良,做出了new和delete运算符

这是new和delete的基础用法,我们在new后面加个小括号里面是需要存放的数据类型,它会帮我们申请一个int类型数据大小的空间就是4字节,第二个是new后面加个类型再用方括号扩起我们需要的数据个数就会给我们申请4个int类型的空间大小即16个字节,而且不需要我们去强转返回指针类型,可以直接接收。并会再申请失败时报异常。可以再后面进行异常的捕捉。但是new出来的空间是没有对应的函数进行内存的扩充的,当我们需要内存扩充的时候需要手动new一个新空间再将旧空间的值拷贝新空间在delete掉旧空间。

delete就是释放空间这里需要对应单个的对应单个的delete,多个数据的调用delete[]。

自定义类型:

C++中有了自定义类型类,类的初始化需要调用构造函数释放需要调用析构函数,但是C语言中的内存管理函数只会帮我们申请空间和交还空间,所以c++的new和delete更多其实就是为了自定义类型而创造出来的,new和delete根据自定义类型申请空间的时候会调用其对应的构造函数,释放时会调用其析构函数。

operator new 和operator delete

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 bytesvoid *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来释放空间的
*/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_FINALLYreturn;}/*free的实现
*/#define   
free(p)               
_free_dbg(p, _NORMAL_BLOCK

如上代码,调用的operator new 和operator delete函数实际上也是通过malloc申请内存空间,和free释放内存空间的。

定位new表达式

定位new表达式用于对一块原始是内存空间进行显示调用自定义类型的构造函数来初始化

紧接着new的括号里面是指向动态开辟的内存空间的指针,紧跟着A类的括号里面是类的初始化列表,若是由无参构造函数可以省略。


http://www.ppmy.cn/server/107154.html

相关文章

《中文Python穿云箭量化平台二次开发技术04》获取股票行情模块HP_tdx的说明、股票代码格式转换及应用示例【股票基本信息资料查询工具】

《中文Python穿云箭量化平台》是纯Python开发的量化平台,因此其中很多Python模块,我们可以自己设计新的量化工具,例如自己新的行情软件、新的量化平台、以及各种量化研究工具。 穿云箭自带指标公式源码运行模块,可以为其他量化平台…

几种前端处理文本换行展示

文章目录 一、使用 CSS 的 white-space 属性二、使用 CSS 的 word-break 和 word-wrap 属性三、 使用 CSS 的 flex 布局和自动换行四、 使用overflow实现换行 一、使用 CSS 的 white-space 属性 可以将 white-space 属性设置为 pre-wrap 或 pre-line。 pre-wrap:保…

【Python-办公自动化】1秒解决海量查找替换难题

欢迎来到"花花 Show Python",一名热爱编程和分享知识的技术博主。在这里,我将与您一同探索Python的奥秘,分享编程技巧、项目实践和学习心得。无论您是编程新手还是资深开发者,都能在这里找到有价值的信息和灵感。 自我介绍: 我热衷于将复杂的技术概念以简单易懂…

Android U WMShell动画调用堆栈

本文主要简单介绍WMShell动画调用堆栈 代码环境:repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android-14.0.0_r7 Systemserver侧 TAG: at com.android.server.wm.Transition.onTransactionReady(Transition.java:1575) TA…

golang笔记——Go堆内存管理

前言 本文主要记录个人学习Golang堆内存管理,涉及到的相关内容,算是对个人所学知识点的梳理与总结。从非常宏观的角度看,Go的堆内存管理就是下图这个样子 学习内存管理,肯定首先需要了解内存管理的基本知识,我会按照 内…

SpringBoot集成kafka-自定义拦截器(可以在拦截器中做记录日志、安全检查等操作)

TOC 1、kafka配置类 kafka配置类添加Configuration注解,springboot启动后会自动读取该配置类;由于在application.yml文件中我们找不到kafak拦截器相关的配置项,因此需要自定义拦截器;消费者相关配置方法中添加自定义拦截器配置&a…

解锁2024音乐新玩法!3款剪辑神器在手,专属BGM创作从此不再难!

嘿,音乐爱好者们,是不是在找那种一听就爱上的背景音乐时感到头疼?每次音乐剪辑时,是不是希望自己能像大师一样,轻松创作出动人的旋律?别担心,到了2024年,我们有了超级工具&#xff0…

Spring核心概念复习AOP

Spring的AOP概念 AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,它允许开发者将横切关注点(如日志记录、事务管理等)从业务逻辑中分离出来,以提高代码的可重用性、可维护性和可扩展性 。AOP 作为 OOP(面向对象编程)的补充,通过动态代理技术,在程序…