C++入门——03内存管理

news2024/9/22 14:41:27

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

1.new和delete操作符

1.1.new/delete操作内置类型

注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[]

如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是:new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申请空间失败时会抛异常,malloc会返回NULL。

1.2 new和delete操作自定义类型

class Test
{
public:
    Test()
        : _data(0)
    {
        cout<<"Test():"<<this<<endl;
    }
    ~Test()
    {
        cout<<"~Test():"<<this<<endl;
    }

private:
    int _data;
};

void Test2()
{
    // 申请单个Test类型的空间
    Test* p1 = (Test*)malloc(sizeof(Test));
    free(p1);
    // 申请10个Test类型的空间
    Test* p2 = (Test*)malloc(sizoef(Test) * 10);
    free(p2);
}


void Test2()
{
    // 申请单个Test类型的对象
    Test* p1 = new Test;
    delete p1;
    // 申请10个Test类型的对象
    Test* p2 = new Test[10];
    delete[] p2;
}

注意:在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与free不会。

1.3. operator new与operator delete函数

new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过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)
    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的原理

  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来释放空间

1.4malloc/free和new/delete的区别

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在释放空间前会调用析构函数完成空间中资源的清理

2.内存泄露

内存泄露(memory leak)指的是在程序中动态分配的内存未被释放,导致这些内存无法再次被使用。内存泄露通常会导致程序的内存占用不断增加,最终可能会导致系统内存耗尽,影响程序的性能和稳定性。

2.1常见原因

  1. 遗漏 deletefree: 在动态分配内存后,如果忘记释放这块内存,就会发生内存泄露。

  2. 多次分配,未释放旧内存: 如果分配了新的内存,但没有释放之前分配的内存,旧内存就会泄露。

  3. 异常情况: 在分配内存后,如果程序遇到异常并退出,没有机会释放内存,可能会导致内存泄露。

  4. 不正确的指针管理: 如指针覆盖、丢失引用等,都会导致无法释放已经分配的内存。

2.2示例代码和分析

以下是一个内存泄露的示例代码:

#include <iostream>
using namespace std;

void CauseMemoryLeak() {
    int* ptr = new int[100]; // 动态分配内存
    // 忘记释放内存
}

int main() {
    CauseMemoryLeak();
    // 内存泄露:动态分配的内存没有释放
    return 0;
}

在这个示例中,CauseMemoryLeak 函数中分配了 100 个 int 的内存,但没有调用 delete[] 来释放内存,从而导致内存泄露。

2.3检测内存泄露

  1. 工具和库

    • Valgrind:一个强大的工具,用于检测内存泄露和其他内存错误。
    • AddressSanitizer:GCC 和 Clang 提供的工具,用于检测内存错误和泄露。
    • Visual Studio 的内存检测工具:用于检测 Windows 平台上的内存问题。
  2. 智能指针

    • 使用 C++11 的 std::unique_ptrstd::shared_ptr 等智能指针,可以自动管理动态分配的内存,从而减少内存泄露的风险。

2.4防止内存泄露

  1. 使用智能指针

    #include <iostream>
    using namespace std;
    
    void CauseMemoryLeak() {
        int* ptr = new int[100]; // 动态分配内存
        // 忘记释放内存
    }
    
    int main() {
        CauseMemoryLeak();
        // 内存泄露:动态分配的内存没有释放
        return 0;
    }
    

  2. 确保配对使用 newdelete

    • 如果使用 new 分配内存,确保在不再需要时使用 delete 释放内存。
  3. 使用容器类

    • 例如 std::vector, std::string 等,这些类会自动管理内存,减少内存泄露的风险。



 

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

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

相关文章

自闭症青年的行为特征有哪些

自闭症&#xff0c;又称孤独症&#xff0c;是一种神经发育障碍&#xff0c;它不仅影响儿童的成长&#xff0c;也会在青年时期展现出一系列独特的行为特征。了解这些特征对于更好地支持和帮助自闭症青年融入社会至关重要。 社交互动方面的困难是自闭症青年较为显著的特征之一。他…

IO进程(学习)2024.8.17

目录 文件属性获取 目录操作 标准IO 和文件IO 的区别 库 库的定义 库的分类 静态库 动态库 库的制作 制作静态库 动态库的制作 使用库 进程 程序和进程的区别 程序&#xff1a;编译好的可执行文件 进程&#xff1a;一个独立的可调度的任务 特点 进程段 进程…

SMS流媒体服务器-MPEG-PS流的深度解析

1.简介 ps流的解析&#xff0c;只要按照标准文档对照16进制的流数据&#xff0c;基本都能看的明白。但是实际项目中会碰到各种各样的问题。本文将对如何高效的解析出音视频数据发表一下个人的看法。 介绍一下本人的开源流媒体&#xff0c;点个star&#xff0c;有兴趣一起开发的…

应急响应:勒索病毒-实战 案例一.【Windows 系统-排查和解密】

什么是勒索病毒. 勒索病毒是一种恶意软件&#xff0c;它通过加密用户的数据或锁定用户设备&#xff0c;然后要求用户支付赎金以解锁数据或系统。勒索病毒的入侵方式多样&#xff0c;包括网络共享文件、捆绑传播、垃圾邮件、水坑攻击、软件供应链传播、暴力破解、利用已知漏洞攻…

javaweb_08:Mybatis入门(基于Springboot)

javaweb_08&#xff1a;Mybatis入门 一、引入二、快速入门&#xff08;一&#xff09;准备工作1、创建Springboot工程2、创建user数据库3、创建实体类 &#xff08;二&#xff09;引入MyBatis相关依赖&#xff0c;配置MyBatis。&#xff08;三&#xff09;编写SQL语句&#xff…

动态路由OSPF基础学习笔记一

由于静态路由由网络管理员手工配置&#xff0c;因此当网络发生变化时&#xff0c;静态路由需要手动调整&#xff0c;这制约了静态路由在现网大规模的应用。 动态路由协议因其灵活性高、可靠性好、易于扩展等特点被广泛应用于现网。在动态路由协议之中&#xff0c;OSPF&#xf…

Linux I/O 多路复用机制详解

文章目录 1 文件描述符&#xff08;File Descriptor&#xff09;1.1 什么是文件描述符&#xff1f;1.2 文件描述符与文件的关系 2 文件描述符集合&#xff08;File Descriptor Set&#xff09;2.1 什么是文件描述符集合&#xff1f;2.2 fd_set 结构体 3 select() 函数的工作原理…

ros笔记06--从零体验ros2中launch系统

ros笔记06--从零体验ros2中launch系统 介绍创建步骤最基础的 launch 案例多节点 launch 案例 注意事项说明 介绍 ROS2系统通常由许多节点组成&#xff0c;这些节点运行在许多不同的进程(甚至不同的机器)上。虽然可以通过 ros2 run 单独运行这些节点&#xff0c;但当节点数量很…

【LLM入门】Let‘s reproduce GPT-2 (124M)【完结,重新回顾一下,伟大!】

文章目录 03:43:05 SECTION 4: results in the morning! GPT-2, GPT-3 repro03:56:21 shoutout to llm.c, equivalent but faster code in raw C/CUDA【太牛了ba】03:59:39 summary, phew, build-nanogpt github repo 03:43:05 SECTION 4: results in the morning! GPT-2, GPT-…

计算机毕业设计选题推荐-springboot 基于springboot的宠物健康顾问系统

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

Windows系统下Go安装与使用

step1&#xff1a; 下载go语言SDK 下载地址&#xff1a;https://go.dev/dl/ 下载后选择合适位置安装即可&#xff0c;我选择D盘 在安装完成后&#xff0c;可以通过go env 命令检测是否安装成功。在“命令提示符”界面输入“go env”命令&#xff0c;如果显示如下类似结果则说明…

C++STL初阶(12):stack和queue的初阶实现

1. stack的选型 对于栈的实现是我们非常熟悉的过程&#xff1a; C语言基础数据结构——栈和队列_栈和队列 插入取出数据-CSDN博客 _top表示下标&#xff0c;_capacity表示空间大小&#xff1a; 那么按照我们原来的思路&#xff0c;利用_top和_capacity T*来给stack构形。 temp…

Grok 2携AI图片生成重生

埃隆马斯克&#xff08;Elon Musk&#xff09;的人工智能初创公司xAI推出其最新的AI助手Grok 2的测试版&#xff0c;添加了类似于OpenAI的DALL-E和Google的Gemini的图像生成工具&#xff0c;但对可以生成的图像类型的限制显然较少。<这是其中的一个“亮点”&#xff0c;一些…

【Hot100】LeetCode—234. 回文链表

目录 1- 思路快慢指针链表拆分反转链表 2- 实现⭐234. 回文链表——题解思路 3- ACM 实现 原题连接&#xff1a;234. 回文链表 1- 思路 快慢指针链表拆分反转链表 思路 ①将链表拆分前后两个部分——>找拆分点、②反转后面部分、③根据反转结果&#xff0c;同时利用两个指…

揭秘住宅IP代理:原理、用途及应用分析

在数字化时代&#xff0c;互联网已成为我们日常生活和工作中不可或缺的一部分。然而&#xff0c;随着网络环境日益复杂&#xff0c;隐私保护、网络访问限制等问题愈发凸显。住宅IP代理作为一种新兴的网络技术解决方案&#xff0c;正逐渐成为众多跨境业务和网络活动的重要工具。…

打卡第46天------动态规划(回文串)

想要快点把每一道题给练会,在面试的时候跟面试官对答如流,这家公司实在是让我没有继续待下去的欲望了,天天祈祷上Di,求Shang帝帮助我实现两份工作的无缝衔接。交托仰望。 今天 我们就要结束动态规划章节了,动态规划的题目还是挺难的,贪心和动态规划对我来说都比较困难,对…

Jeecgboot3.6.3的vue3版本的一种flowable动态增加一个用户任务节点的方法(三)后端代码实现

因为这个项目license问题无法开源,更多技术支持与服务请加入我的知识星球。 这部分主要讲后端实现部分 1、增加一个AddTaskVo 类型,提供新增任务需要的数据结构 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.D…

10结构型设计模式——桥接模式

一、桥接模式 桥接模式&#xff08;Bridge Pattern&#xff09;是结构型的设计模式之一。桥接模式基于类的最小设计原则&#xff0c;通过使用封装&#xff0c;聚合以及继承等行为来让不同的类承担不同的责任。它的主要特点是把抽象&#xff08;abstraction&#xff09;与行为实…

PNG的存储方式[计算机原理]

块的基本理论 众所周知&#xff0c;所有的信息在计算机中以位的形式存在&#xff08;0|1&#xff09;8位是一个字节&#xff0c;可以表示成两个16进制数&#xff0c;例如0xFC因为4位对应一个16进制数嘛。PNG这种图片也不例外&#xff0c;它也是由位组成的&#xff0c;不过我们…

利用Redis获取权限的多种方式

更多实战内容&#xff0c;可前往无问社区查看http://www.wwlib.cn/index.php/artread/artid/10333.html Redis是我们在实战中经常接触到的一款数据库&#xff0c;因其在前期打点中被利用后可直接影响服务器安全所以在攻防过程中也备受红队关注&#xff0c;在本文中会重点分享一…