c++内存管理

简介: c++内存管理

> 作者简介:დ旧言~,目前大二,现在学习Java,c,c++,Python等

> 座右铭:松树千年终是朽,槿花一日自为荣。

> 目标:了解c/c++内存管理,operator new 与operator delete 函数掌握熟练

> 毒鸡汤:愚昧者怨天尤人,无能者长吁短叹,儒弱者颓然放弃。

> 望小伙伴们点赞👍收藏✨加关注哟💕💕

🌟前言

       本篇博客书接上文,我们已经把类和对象学完,好日子要到咯,本篇博客是c++的一个缓冲,有了对c++内存管理的理解,对c++的面向对象更加深刻,在C语言中是面向过程,而在c++是面向对象,像链表,栈和队列直接调用库就行,OK,直接进入今天的主题c++内存管理。

主体  

       咱们从六大板块学习,C/C++内存分布,C语言中内存管理方式,C++中动态内存管理,operator new 与operator delete 函数,浅析定位new表达式(placement-new),内存泄漏。



🌙C/C++内存分布

1.咱们看一个图解:

2.代码分析

globalVar在哪里?_C__ staticGlobalVar在哪里?__C__

staticVar在哪里?__C__ localVar在哪里?_A___

num1 在哪里?___A_

char2在哪里?__A__ *char2在哪里?_A__

pChar3在哪里?__A__ *pChar3在哪里?__D__

ptr1在哪里?__A__ *ptr1在哪里?__B__

选项: A.栈 B.堆 C.数据段 D.代码段

图解:

  • 栈又叫堆栈,非静态局部变量/函数参数/返回值等等,栈是向下增长的。
  • 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。
  • 堆用于程序运行时动态内存分配,堆是可以上增长的。
  • 数据段–存储全局数据和静态数据。
  • 代码段–可执行的代码/只读常量。

🌙C语言中内存管理方式

1、malloc函数

介绍:malloc的全称是memory allocation,中文叫动态内存分配,用于申请一块连续的指定大小的内存块区域以void*类型返回分配的内存区域地址,当无法知道内存具体位置的时候,想要绑定真正的内存空间,就需要用到动态的分配内存,且分配的大小就是程序要求的大小。

放回值:返回的指针指向该分配域的开头位置,否则返回空指针NULL。

2、calloc函数

语法:指针名=(数据类型*)realloc(要改变内存大小的指针名,新的大小)。

新的大小可大可小(如果新的大小大于原内存大小,则新分配部分不会被初始化;如果新的大小小于原内存大小,可能会导致数据丢失 [1-2]

返回值:如果重新分配成功则返回指向被分配内存的指针,否则返回空指针NULL。

3、realloc函数

语法:指针名 = (数据类型*)realloc(要改变内存大小的指针名,新的大小)。

新的大小可大可小(如果新的大小大于原内存大小,则新分配部分不会被初始化;如果新的大小小于原内存大小,可能会导致数据丢失 [1-2] )

返回值:如果重新分配成功则返回指向被分配内存的指针,否则返回空指针NULL。


🌙C++中动态内存管理

💫概念

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

💫new/delete操作内置类型

咱们看下面代码:

int main()
{
    int* p1 = new int;//一个对象
    int* p2 = new int[10];//多个对象,new了10个int
    int* p3 = new int(10);//new了一个对象,初始化成10
    int* p4 = new int[10]{ 10 };//可以通过花括号初始化
    delete p1;
    delete p2;
    delete[] p3;
    delete[] p4;
    return 0;
}    

我们可以通过监视来查看p1,p2,p3,p4等的实际情况:

💫new和delete操作自定义类型

我们简单看一下栈的代码:

class Stack
{
public:
       Stack(int capacity = 10)
       {
              _a = new int[capacity];
              _capacity = capacity;
              _top = 0;
       }
       // 拷贝构造
       // operator=
       ~Stack()
       {
              delete[] _a;
              _capacity = 0;
              _top = 0;
       }
       void Push(int x)
       {
       }
       int top()
       {
              // ...
       }
private:
       int* _a;
       int _top;
       int _capacity;
};
//void StackInit(Stack* ps);
//void StackDestory(Stack* ps);
//
int main()
{
       //Stack st;
       Stack* ps1 = (Stack*)malloc(sizeof(Stack));
       free(ps1);
       Stack* ps2 = new Stack;
//     free(ps2);
       delete ps2;
       return 0;
}

可知调试的结果:

       可以看出new的Stack是有初始化的,而malloc的Stack是没有初始化的而且_a等是私有的,以后想初始化会比较困难。所以:在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与free不会。

mallo和new的相同点和不同点

  • 对应内置类型而言,用malloc和new,没有什么区别。
  • 他们的区别在于自定义类型,malloc只开空间,new可以开空间+调用构造函数初始化。
  • 申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[]。
  • 在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与free不会。
  • 返回值:malloc失败,返回空指针。new失败,抛异常。
  • 其实从底层的角度,new封装了malloc,加上抛异常机制。
  • new T[N]的原理和delete[]的原理

1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请。

2. 在申请的空间上执行N次构造函数。

3. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理。

4. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间。

🌙operator new 与operator delete 函数

1概念

new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是系统提供的。

全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。

2.operator new 和 operator delete的底层逻辑。

operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间失败,尝试执行空间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。

operator delete: 该函数最终是通过free来释放空间的。

3.总结

       operator new 实际也是通过malloc来申请空间,如果malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。operator delete 最终是通过free来释放空间的。

如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是:

new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申

请空间失败时会抛异常,malloc会返回NULL。

🌙浅析定位new表达式(placement-new)

1 内置类型

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

2 自定义类型

  1. new的原理
  • 调用operator new函数申请空间
  • 在申请的空间上执行构造函数,完成对象的构造
  1. delete的原理
  • 在空间上执行析构函数,完成对象中资源的清理工作
  • 调用operator delete函数释放对象的空间
  1. new T[N]的原理
  • 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请
  • 在申请的空间上执行N次构造函数
  1. delete[]的原理
  • 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
  • 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间

🌙内存泄漏

1概念

什么是内存泄漏,内存泄漏的危害?

什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。

内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死。

2内存泄漏的分类

第一种:堆内存泄漏(Heap leak)

堆内存指的是程序执行中依据须要分配通过malloc / calloc / realloc / new等从堆中分配的一块内存,

用完后必须通过调用相应的 free或者delete 删掉。假设程序的设计错误导致这部分内存没有被释放,那么以后这部分空间将无法再被使用,就会产生Heap Leak。

第二种:系统资源泄漏

指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放掉,导致系统

资源的浪费,严重可导致系统效能减少,系统执行不稳定。

3如何避免内存泄漏

1. 工程前期良好的设计规范,养成良好的编码规范,申请的内存空间记着匹配的去释放。注意:这个理想状态。但是如果碰上异常时,就算注意释放了,还是可能会出问题。需要下一条智能指针来管理才有保证。

2. 采用RAII思想或者智能指针来管理资源。

3. 有些公司内部规范使用内部实现的私有内存管理库。这套库自带内存泄漏检测的功能选项。

4. 出问题了使用内存泄漏工具检测。ps:不过很多工具都不够靠谱,或者收费昂贵。

🌟结束语

      今天内容就到这里啦,时间过得很快,大家沉下心来好好学习,会有一定的收获的,大家多多坚持,嘻嘻,成功路上注定孤独,因为坚持的人不多。那请大家举起自己的小说手给博主一键三连,有你们的支持是我最大的动力💞💞💞,回见。

目录
相关文章
|
24天前
|
存储 程序员 编译器
玩转C++内存管理:从新手到高手的必备指南
C++中的内存管理是编写高效、可靠程序的关键所在。C++不仅继承了C语言的内存管理方式,还增加了面向对象的内存分配机制,使得内存管理既有灵活性,也更加复杂。学习内存管理不仅有助于提升程序效率,还有助于理解计算机的工作原理和资源分配策略。
|
3月前
|
存储 缓存 编译器
【硬核】C++11并发:内存模型和原子类型
本文从C++11并发编程中的关键概念——内存模型与原子类型入手,结合详尽的代码示例,抽丝剥茧地介绍了如何实现无锁化并发的性能优化。
213 68
|
22天前
|
安全 C语言 C++
彻底摘明白 C++ 的动态内存分配原理
大家好,我是V哥。C++的动态内存分配允许程序在运行时请求和释放内存,主要通过`new`/`delete`(用于对象)及`malloc`/`calloc`/`realloc`/`free`(继承自C语言)实现。`new`分配并初始化对象内存,`delete`释放并调用析构函数;而`malloc`等函数仅处理裸内存,不涉及构造与析构。掌握这些可有效管理内存,避免泄漏和悬空指针问题。智能指针如`std::unique_ptr`和`std::shared_ptr`能自动管理内存,确保异常安全。关注威哥爱编程,了解更多全栈开发技巧。 先赞再看后评论,腰缠万贯财进门。
103 0
|
2月前
|
存储 程序员 编译器
什么是内存泄漏?C++中如何检测和解决?
大家好,我是V哥。内存泄露是编程中的常见问题,可能导致程序崩溃。特别是在金三银四跳槽季,面试官常问此问题。本文将探讨内存泄露的定义、危害、检测方法及解决策略,帮助你掌握这一关键知识点。通过学习如何正确管理内存、使用智能指针和RAII原则,避免内存泄露,提升代码健壮性。同时,了解常见的内存泄露场景,如忘记释放内存、异常处理不当等,确保在面试中不被秒杀。最后,预祝大家新的一年工作顺利,涨薪多多!关注威哥爱编程,一起成为更好的程序员。
|
4月前
|
存储 缓存 C语言
【c++】动态内存管理
本文介绍了C++中动态内存管理的新方式——`new`和`delete`操作符,详细探讨了它们的使用方法及与C语言中`malloc`/`free`的区别。文章首先回顾了C语言中的动态内存管理,接着通过代码实例展示了`new`和`delete`的基本用法,包括对内置类型和自定义类型的动态内存分配与释放。此外,文章还深入解析了`operator new`和`operator delete`的底层实现,以及定位new表达式的应用,最后总结了`malloc`/`free`与`new`/`delete`的主要差异。
94 3
|
4月前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
290 4
|
5月前
|
存储 程序员 编译器
简述 C、C++程序编译的内存分配情况
在C和C++程序编译过程中,内存被划分为几个区域进行分配:代码区存储常量和执行指令;全局/静态变量区存放全局变量及静态变量;栈区管理函数参数、局部变量等;堆区则用于动态分配内存,由程序员控制释放,共同支撑着程序运行时的数据存储与处理需求。
311 22
|
5月前
|
程序员 C++ 容器
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
|
5月前
|
存储 C语言 C++
【C++打怪之路Lv6】-- 内存管理
【C++打怪之路Lv6】-- 内存管理
73 0
【C++打怪之路Lv6】-- 内存管理
|
5月前
|
存储 C语言 C++
【C/C++内存管理】——我与C++的不解之缘(六)
【C/C++内存管理】——我与C++的不解之缘(六)