C++基础-资源管理:堆、栈与 RAII_c++heap内存堆管理-程序员宅基地

技术标签: c++  C++开发  RAII  堆栈  动态内存分配  heap和stack  

基本概念

,英文是 heap,在内存管理的语境下,指的是动态内存分配的区域,和数据结构中的“大根堆和小根堆”不是一个概念。同时,这里堆分配的内存需要手工释放,否则会造成内存泄漏。
C++ 标准里有一个和堆相关的概念是自由存储区,英文是 free store,特指使用 newdelete 来分配和释放内存的区域。一般而言,这是堆的一个子集:

  • newdelete 操作的区域是 free store
  • mallocfree 操作的区域是 heap

newdelete 通常底层使用 malloc 和 free 来实现,所以 free store 也是 heap,对其区分的实际意义不大,两者可以等同。

,英文是 stack,在内存管理的语境下,指的是函数调用过程中产生的本地变量和调用数据的区域。这个栈和数据结构里的栈高度相似,都满足“后进先出”(last-in-first-out 或 LIFO)。
RAII,完整的英文是 Resource Acquisition Is Initialization,是 C++ 所特有的资源管理方式。RAII 依托栈和析构函数,来对所有的资源——包括堆内存在内——进行管理。对 RAII 的使用,使得 C++ 不需要类似于 Java 那样的垃圾收集方法,也能有效地对内存进行管理。

综上,C++ 程序中的内存分为两个部分:

  • :在函数内部声明的所有变量都将占用栈内存。
  • :这是程序中未使用的内存,在程序运行时可用于动态分配内存。

在 C++ 里,这种情况下有 99% 的可能性不应该使用堆内存分配,而应使用栈内存分配。

C++ 使用如下代码在堆上分配内存:

auto ptr = new std::vector<int>(n,t )  // 构造包含 n 个初始值为 t 的元素的容器

在堆上分配内存 c++/java 使用 new 关键字,python 是隐式构造,不需要特殊关键字,这个过程会涉及到三个可能的内存管理器操作:

  1. 内存管理器分配指定大小的内存,可用内存不足时要从操作系统申请新的内存。
  2. 释放内存时除了把内存标记为不使用,还要将其合并在一起,防止内存碎片化。
  3. c++ 不适用垃圾回收,java/python 中有这个操作。

因为程序运行异常导致 new 的内存没有通过 delete 释放掉,叫作 ”内存泄漏“。

首先通过下面示例代码来说明 C++ 里函数调用、本地变量是如何使用栈的。

void foo(int n)
{
  …
}
void bar(int n)
{
  int a = n + 1;
  foo(a);
}
int main()
{
  …
  bar(42);
  …
}

代码执行过程中,操作系统栈的变化情况如下:
在这里插入图片描述
通过上图示例可以知道,是向上增长的。在包括 x86 在内的大部分计算机体系架构中,栈的增长方向是低地址,因而上方意味着低地址。

  1. 函数调用另一个函数时,先把参数压入栈中,再把下一行汇编指令的地址压入栈,并跳转到调用的那个函数;
  2. 进入新函数后,需要做必须的保存工作,调整栈指针,分配出本地变量所需的空间;
  3. 执行函数中的代码,执行完毕后,根据调用者压入栈的地址,返回到调用者未执行的代码中继续执行。

本地变量所需的内存在栈上,跟函数执行所需的其他数据在一起。当函数执行完成之后,这些内存也就自然而然释放掉了。可以看到:

  • 栈上的分配极为简单,移动一下栈指针而已。
  • 栈上的释放也极为简单,函数执行结束时移动一下栈指针即可。
  • 由于后进先出的执行过程,不可能出现内存碎片。

RAII

RAII 源于 C++,在 Java,C#,D,Ada,Vala 和 Rust 中也有应用。

RAII,全称资源获取即初始化(英语:Resource Acquisition Is Initialization),它是在一些面向对象语言中的一种惯用法,是 C++ 语言的一种管理资源、避免内存泄漏的方法。在计算机系统中,资源是数量有限且对系统正常运行具有一定作用的元素。比如:网络套接字、互斥锁、文件句柄和内存等等。系统资源是有限的,所以在程序中使用系统资源都必须遵循如下步骤:

  1. 申请资源;
  2. 使用资源;
  3. 释放资源。

RAII 要求,资源的有效期与持有资源的对象的生命期严格绑定,即由对象的构造函数完成资源的分配(获取),同时由析构函数完成资源的释放。在这种要求下,只要对象能正确地析构,就不会出现资源泄露问题。

如何使用 RAII

由于系统的资源不具有自动释放的功能,而 C++ 中的类具有自动调用析构函数的功能。如果把资源用类进行封装起来,对资源操作都封装在类的内部,在析构函数中进行释放资源。当定义的局部变量的生命结束时,它的析构函数就会自动的被调用,如此,就不用程序员显示的去调用释放资源的操作了。

参考资料

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_20986663/article/details/126892153

智能推荐

CDN架构原理、流量模型、网络调优_cdn 95带宽算法优化-程序员宅基地

文章浏览阅读1k次。详细的知识参考 :https://www.cnblogs.com/zousong/p/10925445.htmlCDN全称:Content Delivery Network或Content Ddistribute Network,即内容分发网络基本思路:尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络,CDN系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离.._cdn 95带宽算法优化

nodejs安装之后,npm命令拒绝访问_npm -v 拒绝访问-程序员宅基地

文章浏览阅读5.7k次。@[T标题OC](这里写自定义目录标题)欢迎使用Markdown编辑器你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。新的改变我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博..._npm -v 拒绝访问

单片机通信接口:UART、I2C、SPI、TTL、RS232、RS422、RS485、CAN、USB_单片机通讯接口-程序员宅基地

文章浏览阅读1.5w次,点赞40次,收藏325次。参考资料:这些单片机接口,一定要熟悉:UART、I2C、SPI、TTL、RS232、RS422、RS485、CAN、USB、SD卡秒懂所有USB接口类型,USB接口大全1. UARTUART(通用异步收发器)指的是一种物理接口形式(硬件)。UART是异步,全双工串口总线。它比同步串口复杂很多。有两根线,一根TXD用于发送,一根RXD用于接收。UART的串行数据传输不需要使用时钟信号来同步传输,而是依赖于发送设备和接收设备之间预定义的配置。对于发送设备和接收设备来说,两者的串行通信配置应该设_单片机通讯接口

11个经典运放电路_运算放大器11种经典电路-程序员宅基地

文章浏览阅读10w+次,点赞205次,收藏1.3k次。运算放大器组成的电路五花八门,令人眼花瞭乱。工程师在分析它的工作原理时常抓不住核心,令人头大。为此小编特地搜罗天下运放电路之应用,来个“庖丁解牛”,希望各位看完后有所收获。遍观所有模拟电子技术的书籍和课程,在介绍运算放大器电路的时候,无非是先给电路来个定性,比如这是一个同向放大器,然后去推导它的输出与输入的关系,然后得出Vo=(1+Rf)Vi,那是一个反向放大器,然后得出Vo=-Rf*V..._运算放大器11种经典电路

s905各种型号的区别_预行式增压缸和直压增压缸有什么区别?-程序员宅基地

文章浏览阅读359次。玖容增压缸的型号有很多,适用在不同的工作环境中,不同的型号是根据不同的使用环境来设计的。我们从工作原理上来划分,增压缸一般分为预行式增压缸和直压增压缸,它们由于使用的环境不同,使用的场合也有所不同,今天就来和大家来分享一下“预行式增压缸和直压增压缸有什么区别?”。首先我们来说说预行式增压缸和直压增压缸的区别之处:预行式增压缸比直压增压缸多了一段预走行程。将增压器直接设计在气缸的后端,接上气压管路,..._玖容 新浪博客

运维面试题-程序员宅基地

文章浏览阅读8.5k次,点赞10次,收藏98次。NETWORK1 请描述 TCP/IP 协议中主机与主机之间通信的三要素参考答案IP 地址(IP address)子网掩码(subnet mask)IP 路由(IP router)2 请描述 IP 地址的分类及每一类的范围参考答案A 类 1-26B 类 128-191C 类 192-223D 类 224-239 组播(多播)E 类 240-254 科研3 请描述 A、B、..._运维面试题

随便推点

Linux终端(Terminal)与控制台(Console)的区别_linux c terminal-程序员宅基地

文章浏览阅读976次。Linux终端(Terminal)与控制台(Console)的区别_linux c terminal

制作 linux .deb 安装包_构建deb软件升级包-程序员宅基地

文章浏览阅读371次。ubuntu 制作安装包_构建deb软件升级包

(转载)循序渐进学习嵌入式Linux开发技术-程序员宅基地

文章浏览阅读39次。再次申明,本文是转载,为以后查找留个记号。嵌入式时代已经来临,你还在等什么? ---循序渐进学习嵌入式开发技术最近经常有用人单位给我打来电话,问我这有没有嵌入式Linux方面的开发人员,他们说他们单位急需要懂得在嵌入式linux环境下的软件开发人员,我回答说,现在每年毕业的大学生那么多,还招不到合适的软件开发人员吗?他跟我说,毕业大学生虽然多,但大部分都能力不够,不能达到他们的工作的要...

如何成功在M1 macbook上运行Ubuntu20.04_ubuntu20.04 for m1-程序员宅基地

文章浏览阅读8.3k次,点赞5次,收藏19次。如何在搭载M1芯片的苹果电脑上跑UbuntuParallels官方发布了针对搭载apple silcon M1芯片的Mac的测试版虚拟机,笔者已经成功运行,具体步骤总结如下:第一步 安装测试版 Parallels Desktop需要去官网注册账户然后下载专门的测试软件参考地址:官网地址步骤如下:Meet the new Parallels Desktop (官网页面To run a virtual machine on a new Mac computer with the Apple M1 _ubuntu20.04 for m1

STM32单片机智能手环心率计步器体温-程序员宅基地

文章浏览阅读654次,点赞9次,收藏15次。STM32F103C8T6单片机核心板电路、ADXL345传感器电路、心率传感器电路、温度传感器和lcd1602电路组成。通过重力加速度传感器ADXL345检测人的状态,计算出走路步数、走路距离和平均速度。过心率传感器实时检测心率,通过温度传感器检测温度。通过LCD1602实时显示步数、距离和平均速度、心率以及温度值。主要学习ADXL345,心率传感器等等。

Pandas 修改index_pandas修改df index-程序员宅基地

文章浏览阅读190次。Pandas 修改index。_pandas修改df index