C++初学者指南第一步---10.内存(基础)

C++初学者指南第一步---10.内存(基础)

文章目录

  • C++初学者指南第一步---10.内存(基础)
    • 1.内存模型
      • [1.1 纸上谈兵:C++的抽象内存模型](#1.1 纸上谈兵:C++的抽象内存模型)
      • [1.2 实践:内存的实际处理](#1.2 实践:内存的实际处理)
    • [2. 自动存储](#2. 自动存储)
    • 3.动态存储:std::vector
      • [3.1 动态内存分配](#3.1 动态内存分配)
      • [3.2 std::vector 内存布局](#3.2 std::vector 内存布局)
      • [3.3 std::vector 扩容方案](#3.3 std::vector 扩容方案)
      • [3.4 std::vector的大小(size)和容量(capacity)](#3.4 std::vector的大小(size)和容量(capacity))
      • [3.5 std::vector内存生命周期示例](#3.5 std::vector内存生命周期示例)

1.内存模型

1.1 纸上谈兵:C++的抽象内存模型

C++ 的语言规范基于抽象内存模型。

具体实现(编译器,C++运行时等)可以采用不同策略来满足具体平台(CPU架构,操作系统等)上的这些规范。

内存组织

示例:std::int16_t i = 1234; 是一个名为 i 的对象,大小为 2 字节(= 16 位),值为 0000010011010010,
根据其类型 int16_t 表示数字 1234。

请注意,抽象模型并没有涉及到内存是如何划分的,也不涉及缓存层次结构。

对象存储持续时间类型

自动 对象生存期绑定到 { ... } 块作用域的开始到结束 局部变量、函数参数
动态 通过特殊指令控制对象寿命 可以按需创建/销毁且独立于块作用域的对象
线程 与线程的开始和结束相关的对象生存期 每线程存储
静态 对象生存期与程序的开始和结束相关联 单例

1.2 实践:内存的实际处理

C++内存模型的实际实现

  • 受到目标平台的功能和限制的限制 (CPU/内存架构、操作系统、编译器)
  • 需要修复C++标准留下的选项,例如字节中的位数(在大多数平台上为8)
  • 需要支持c++标准描述的对象存储期/生命周期方案(自动、动态、线程、静态)

常见的解决方案:自动/动态存储期专用内存分区

HEAP 堆(也被称为自由存储区)

  • 用于动态存储期对象,例如std::vector的内容
  • 空间大:可用于大容量存储(大部分主内存)
  • 根据需要分配和释放任何对象。
  • 无序分配和释放 ⇒ 导致内存碎片化
  • 分配缓慢:需要为新对象找到连续的空置空间

STACK 栈(堆栈)

  • 用于自动存储期的局部变量、函数参数对象等。
  • 空间小(通常只有几 MB)
  • 快速分配:新对象始终放在顶部
  • 以创建的相反顺序释放分配的对象
  • 无法释放分配在最顶部以下的对象 (= 最新)

2. 自动存储

栈通常用于自动存储期的对象如局部变量(包括函数参数):

<1>

<2>

<3>
<4>

<5>

<6>

<7>

<8>

<9>

<10>

3.动态存储:std::vector

3.1 动态内存分配

当前:只使用std::vector

后面:使用更多的标准库容器(set、map...)

再后面:手动动态内存分配

在现代 C++ 中,手动分配内存实际上只有在你想要实现自己的动态数据结构/容器时才是真正必要的。

3.2 std::vector 内存布局

  • 每个向量对象都有一个单独的缓冲区,该缓冲区是动态分配的(在堆上),实际内容存储在其中。

  • 现在我们只知道如何在栈上分配对象,但向量对象 v 本身也可以在堆上分配(更多内容请参阅后面的章节)。

    vector<int> v {0,1,2,3,4};

3.3 std::vector 扩容方案

  • 分配后的内存块无法调整大小!(之前分配的内存块后面不一定有剩余空间)
  • 动态数组实现将数组对象与用于存储值的实际内存块分开。
  • 然后通过以下方式进行扩容:
    1. 动态分配新的、(≈1.1-2×)更大的内存块
    2. 将旧值复制/移动到新块
    3. 释放旧的、较小的内存块

      动态数组(维基百科)

3.4 std::vector的大小(size)和容量(capacity)

  • .size()→ 向量中的元素数量
  • .resize(新的元素数量)
  • . capacity() → 可以使用的内存槽数量(容量)
  • .reserve(新的容量)

    注意:如果您大概知道元素的数量 ⇒ 在将元素添加到向量之前先进行预留(reserve)!
    这样可以避免在增长阶段时进行不必要的内存分配和复制。

3.5 std::vector内存生命周期示例

<1>

<2>

<3>

<4>

<5>

<6>

<7>

<8>

<9>

<10>

<11>

<12>

<13>

<14>

<15>

附上原文链接

如果文章对您有用,请随手点个赞,谢谢!^_^

相关推荐
Monly213 分钟前
Java(若依):修改Tomcat的版本
java·开发语言·tomcat
boligongzhu4 分钟前
DALSA工业相机SDK二次开发(图像采集及保存)C#版
开发语言·c#·dalsa
Eric.Lee20214 分钟前
moviepy将图片序列制作成视频并加载字幕 - python 实现
开发语言·python·音视频·moviepy·字幕视频合成·图像制作为视频
小俊俊的博客5 分钟前
海康RGBD相机使用C++和Opencv采集图像记录
c++·opencv·海康·rgbd相机
7yewh7 分钟前
嵌入式Linux QT+OpenCV基于人脸识别的考勤系统 项目
linux·开发语言·arm开发·驱动开发·qt·opencv·嵌入式linux
waicsdn_haha18 分钟前
Java/JDK下载、安装及环境配置超详细教程【Windows10、macOS和Linux图文详解】
java·运维·服务器·开发语言·windows·后端·jdk
_WndProc20 分钟前
C++ 日志输出
开发语言·c++·算法
薄荷故人_22 分钟前
从零开始的C++之旅——红黑树及其实现
数据结构·c++
m0_7482400222 分钟前
Chromium 中chrome.webRequest扩展接口定义c++
网络·c++·chrome
qq_4335545429 分钟前
C++ 面向对象编程:+号运算符重载,左移运算符重载
开发语言·c++