C++基础之内存管理

news2024/10/21 10:19:46

目录

1,堆(heap)使用要点总结

2,栈(stack)使用要点总结

3,RAII思想使用总结

4,常用的优化内存管理技术

4.1,内存池

4.2,智能指针 

4.3,内存泄露检测工具 

5,C++17 std::pmr内存框架

5.1,为什么需要std::pmr

5.2,std::pmr核心概念

5.3,std::pmr的使用


1,堆(heap)使用要点总结

  • 动态分配内存的区域,使用 new 和 delete 或 malloc 和 free 进行内存分配和释放。如果没有手动释放,可能会造成内存泄漏。
int* ptr = new int; // 分配一个int大小的内存
*ptr = 10; // 初始化内存
delete ptr; // 释放内存
//使用new[]创建数组
int* arr = new int[10]; // 分配一个int数组
for (int i = 0; i < 10; ++i) {
    arr[i] = i;
}
delete[] arr; // 释放数组
  • new 和 delete 是 C++ 中的运算符,malloc 和 free 是 C 语言中的函数,虽然在 C++ 中也可以使用,但通常更推荐使用newdelete,因为它们支持构造和析构操作,这对于对象的生命周期管理至关重要。
int* ptr = (int*)malloc(sizeof(int)); // 分配内存
*ptr = 10; // 初始化内存
free(ptr); // 释放内存

2,栈(stack)使用要点总结

  • 栈内存管理是函数调用过程中用于存储本地变量和调用数据的区域。
  • 栈是后进先出(LIFO)的结构。在大多数计算机架构中,栈从高地址向低地址增长。
  • 每次函数调用时,会将参数和返回地址压入栈中。函数执行结束时,栈指针会复位到调用该函数前的位置,释放该函数使用的栈空间。
  • 栈上的内存分配和释放非常高效和简单,只需移动栈指针即可。

3,RAII思想使用总结

  • RAII 是 C++ 中管理资源的一种惯用手法,保证资源在对象生命周期内的正确分配和释放。
  • 对象可以存储在栈上或堆上,但在许多情况下,对象不应存在栈上,例如对象非常大或大小在编译时无法确定。
  • RAII 的核心思想是将资源的获取与对象的生命周期绑定,在对象的构造函数中获取资源,并在析构函数中释放资源。
  • RAII思想除了广泛应用于内存管理,还可用于文件句柄、同步锁等关键资源的管理。
#include <fstream>

class FileHandle {
public:
    FileHandle(const char* filename) {
        file_.open(filename);
    }

    ~FileHandle() {
        if (file_.is_open()) {
            file_.close();
        }
    }

    // 禁止复制构造和赋值操作
    FileHandle(const FileHandle&) = delete;
    FileHandle& operator=(const FileHandle&) = delete;

private:
    std::ofstream file_;
};

 在上述示例中,FileHandle类在构造函数中打开文件,并在析构函数中关闭文件。这样,只要FileHandle对象的生命周期结束,文件就会自动关闭,从而避免了资源泄漏。

4,常用的优化内存管理技术

4.1,内存池

内存池是一种优化动态内存分配的技术,它预先分配一大块内存,并从中分配小块内存给请求者。这样可以减少内存碎片,并提高内存分配的效率。

class MemoryPool {
public:
    MemoryPool(size_t poolSize) {
        pool_ = new char[poolSize];
        freeList_ = pool_;
    }

    ~MemoryPool() {
        delete[] pool_;
    }

    void* allocate(size_t size) {
        // 实现内存分配逻辑
    }

    void deallocate(void* pointer) {
        // 实现内存释放逻辑
    }

private:
    char* pool_;
    char* freeList_;
};

4.2,智能指针 

智能指针是一种自动管理动态分配内存的类,可以自动释放内存,避免内存泄漏。C++11引入了几种智能指针,如std::unique_ptrstd::shared_ptrstd::weak_ptr

#include <memory>

std::unique_ptr<int> uniquePtr(new int(10));
std::shared_ptr<int> sharedPtr(new int(20));

4.3,内存泄露检测工具 

C++有多种工具可以帮助检测内存泄漏,如Valgrind、AddressSanitizer等。这些工具可以在程序运行时监控内存分配和释放,帮助我们定位内存泄漏的位置,快速排查解决问题。

  • Valgrind

开源框架,通过模拟CPU环境来检测程序中的内存问题。Memcheck是最常用的模块,用于检测内存泄漏、内存越界等问题。运行命令如下

valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes ./program_name

优点:

能够检测多种内存问题,如内存泄漏、内存越界等;

提供详细的错误报告,包括泄漏的大小和在代码中的位置。

缺点:

运行被检测的程序时会显著变慢。

  • AddressSanitizer(ASAN)

ASAN 是一个快速的内存错误检测器,它可以检测使用已释放内存、堆内存越界、栈内存越界等问题。它通过编译时插桩来检测错误。使用时需要在编译语句中增加开启:

g++ -fsanitize=address -g test_program.cpp -o test_program

优点:

检测速度快,对程序性能的影响较小;

可以与现有的调试工具一起使用。

缺点:

可能会增加编译后的程序大小。

5,C++17 std::pmr内存框架

C++17 引入的 std::pmrPolymorphic Memory Resource多态内存资源)框架,是对C++内存管理系统的一个重要扩展,使得内存分配器可以更加灵活地管理内存分配策略,特别是在容器等数据结构中,通过这种方法,可以为不同的容器指定不同的内存资源,提供更灵活的内存管理选项。

5.1,为什么需要std::pmr

std::vector、std::string 等标准库容器中,默认情况下内存分配是通过全局的 new/delete 来进行的,无法轻松地更改这些容器的内存分配策略。例如:

  • 提高性能:在某些高性能场景下,可能需要对容器中的内存进行优化,比如使用内存池或固定大小的内存块。
  • 减少内存碎片:特别是在嵌入式系统中,内存池能够帮助减少动态内存分配带来的碎片化问题。
  • 共享内存资源:多个容器可以共享同一块内存资源,而无需各自管理内存,这样能减少内存使用量。

C++17 的 std::pmr 提供了一种灵活的方式,使得我们可以控制内存的分配方式,从而优化内存的使用和性能 。

5.2,std::pmr核心概念

std::pmr 框架中引入了以下几个重要概念:

Memory Resource(内存资源):负责实际的内存分配与释放操作。

  • std::pmr::new_delete_resource():默认的内存资源,使用 ::operator new::operator delete 进行内存管理。
  • std::pmr::monotonic_buffer_resource:单调分配器,用于分配一块大内存并逐步使用,不支持个别对象的释放,适合短生命周期的对象。
  • std::pmr::unsynchronized_pool_resource:无锁内存池,适合单线程环境。
  • std::pmr::synchronized_pool_resource:线程安全的内存池。

Polymorphic Allocator(多态分配器):是一种可以在运行时绑定不同内存资源的分配器,允许在使用标准库容器时自定义内存分配策略。

Memory Resource Hierarchy(内存资源层次)std::pmr 提供了几个预定义的内存资源,并且用户可以定义自己的内存资源。

5.3,std::pmr的使用

std::pmr::polymorphic_allocatorstd::pmr 框架中的核心类之一,它可以用作标准库容器的自定义分配器。这允许程序员使用不同的内存资源管理容器的内存分配。

#include <iostream>
#include <vector>
#include <memory_resource>  // std::pmr 需要包含此头文件

int main() {
    // 准备一个内存缓冲区,大小为1024字节
    char buffer[1024];

    // 创建一个 monotonic_buffer_resource,使用上面的 buffer 作为内存池
    std::pmr::monotonic_buffer_resource resource(buffer, sizeof(buffer));

    // 使用该资源创建 polymorphic_allocator
    std::pmr::polymorphic_allocator<int> allocator(&resource);

    // 使用该 allocator 创建 std::pmr 容器(如 vector)
    std::pmr::vector<int> vec(allocator);

    // 向 vector 中添加一些元素
    for (int i = 0; i < 10; ++i) {
        vec.push_back(i);
    }

    // 输出 vector 中的元素
    for (int i : vec) {
        std::cout << i << " ";
    }
    std::cout << std::endl;

    // 注意:使用 monotonic_buffer_resource 后,内存不会被单独释放,
    // 而是等整个 buffer 被重用或者整个资源被销毁时释放
    return 0;
}

在线程安全环境使用std::pmr

#include <iostream>
#include <vector>
#include <memory_resource>

int main() {
    // 创建一个线程安全的内存池
    std::pmr::synchronized_pool_resource pool;

    // 创建分配器,使用 synchronized_pool_resource
    std::pmr::polymorphic_allocator<int> allocator(&pool);

    // 使用自定义的分配器创建 vector
    std::pmr::vector<int> vec(allocator);

    // 向 vector 中添加一些元素
    for (int i = 0; i < 10; ++i) {
        vec.push_back(i);
    }

    // 输出 vector 中的元素
    for (int i : vec) {
        std::cout << i << " ";
    }
    std::cout << std::endl;

    return 0;
}

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

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

相关文章

Git极速入门

git初始化 git -v git config --global user.name "" git config --global user.email "" git config --global credential.helper store git config --global --list省略(Local) 本地配置&#xff0c;只对本地仓库有效–global 全局配置&#xff0c;所有…

spring boot yml文件中引用*.properties文件中的属性

1、首先在*.properties文件中加入一个属性&#xff0c;如&#xff1a; 2、然后再application.yml文件中通过${jdbc.driver}来引用&#xff0c;如&#xff1a; 3、然后再创建一个资源配置类&#xff0c;通过PropertySource来引入这个*.properties文件&#xff0c;如&#xff1…

JDK中socket源码解析

目录 1、Java.net包 1. Socket通信相关类 2. URL和URI处理类 3. 网络地址和主机名解析类 4. 代理和认证相关类 5. 网络缓存和Cookie管理类 6. 其他网络相关工具类 2、什么是socket&#xff1f; 3、JDK中socket核心Api 4、核心源码 1、核心方法 2、本地方法 3、lin…

基于stm32的esp8266的WIFI控制风扇实验

实验案例&#xff37;&#xff29;&#xff26;&#xff29;控制风扇 项目需求 电脑通过esp8266模块远程遥控风扇。 项目框图 ​ 风扇模块封装 #include "sys.h" #include "fan.h"void fan_init(void) {GPIO_InitTypeDef gpio_initstruct;//打开时钟…

4K Mini-LED显示器平民价,一千多的联合创新27M3U到底有多香

哈喽小伙伴们好&#xff0c;我是Stark-C~ 要说前几年买显示器还是普通IPS的天下&#xff0c;那个时候虽说也有MiniLED或者OLED显示器&#xff0c;但是价格那也是真贵啊&#xff0c;毕竟那个时候MiniLED和OLED还没普及&#xff0c;只有一些高档电视或者显示器才会用到此技术。不…

OpenCV高级图形用户界面(18)手动设置轨迹条(Trackbar)的位置函数setTrackbarPos()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 该函数设置指定窗口中指定轨迹条的位置。 注意 [仅 Qt 后端] 如果轨迹条附加到控制面板&#xff0c;则 winname 可以为空。 函数原型 void cv…

三周精通FastAPI:4 使用请求从客户端(例如浏览器)向 API 发送数据

FastAPI官网手册&#xff1a;https://fastapi.tiangolo.com/zh/tutorial/query-params/ 上节内容&#xff1a;三周精通FastAPI&#xff1a;3 查询参数 请求 FastAPI 使用请求从客户端&#xff08;例如浏览器&#xff09;向 API 发送数据。 请求是客户端发送给 API 的数据。响…

国家信息安全水平考试(NISP一级)最新题库-第十六章

目录 另外免费为大家准备了刷题小程序和docx文档&#xff0c;有需要的可以私信获取 1 防火墙是一种较早使用、实用性很强的网络安全防御技术&#xff0c;以下关于防火墙说法错误的是&#xff08;&#xff09; A.防火墙阻挡对网络的非法访问和不安全数据的传递&#xff1b;B.防…

Leecode刷题之路第27天之移除元素

题目出处 27-移除元素-题目描述 题目描述 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。假设 nums 中不等于 val 的元素数量为 k&#xff0c;要通过此题&#x…

C++ | Leetcode C++题解之第491题非递减子序列

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<int> temp; vector<vector<int>> ans;void dfs(int cur, int last, vector<int>& nums) {if (cur nums.size()) {if (temp.size() > 2) {ans.push_back(temp);}return;}if…

【题解】—— LeetCode一周小结42

&#x1f31f;欢迎来到 我的博客 —— 探索技术的无限可能&#xff01; &#x1f31f;博客的简介&#xff08;文章目录&#xff09; 【题解】—— 每日一道题目栏 上接&#xff1a;【题解】—— LeetCode一周小结41 14.鸡蛋掉落 题目链接&#xff1a;887. 鸡蛋掉落 给你 k 枚…

c++迷宫游戏

1、问题描述 程序开始运行时显示一个迷宫地图&#xff0c;迷宫中央有一只老鼠&#xff0c;迷宫的右下方有一个粮仓。游戏的任务是使用键盘上的方向健操纵老鼠在规定的时间内走到粮仓处。 基本要求: 老鼠形象可以辨认,可用键盘操纵老鼠上下左右移动&#xff1b;迷宫的墙足够结…

博弈论学习笔记【施工中】

SG函数 首先定义就不用我讲了吧&#xff0c;还不会的自己看看 传送门 再进一步理解一下吧&#xff1a; 黑色数字是节点编号&#xff0c;红色是 S G SG SG 函数值 看下它的过程&#xff1a; 首先 5 5 5 和 6 6 6 没有后继节点&#xff0c;为必败态&#xff0c;先赋值为 …

OpenCV和HALCON

OpenCV和HALCON是两种广泛用于图像处理和计算机视觉的开发库&#xff0c;它们各有优缺点&#xff0c;适合不同的应用场景。以下是两者的比较&#xff1a; 1. 开发背景与定位 OpenCV (Open Source Computer Vision Library)&#xff1a; 开源库&#xff0c;最初由Intel开发&…

【图解版】力扣第146题:LRU缓存

力扣第146题&#xff1a;LRU缓存 一、LRU算法1. 基本概念2. LRU 和 LFU 的区别&#xff1a;3. 为什么 LRU 不需要记录使用频率&#xff1f; 二、Golang代码实现三、代码图解1. LRUCache、DLinkedNode两个结构体2. 初始化结构体对象3. addToHead函数4. removeNode函数5. moveToH…

基于单片机的多功能鱼缸控制系统设计

本设计以STC12C5A60S2单片机为核心的多功能鱼缸控制系统&#xff0c;该系统可分别利用温度传感器、水位传感器和浑浊度传感器来检测鱼缸内部的水温、液体高度和浑浊程度&#xff0c;并在显示屏上进行显示。若检测结果超出阈值范围&#xff0c;则继电器工作从而控制内部环境。通…

LeetCode102. 二叉树的层序遍历(2024秋季每日一题 43)

给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[[3],[9,20],[15,7]] 示例 2&#xff1a; 输入…

白嫖正版xshell和XFTP

在哪里可以下载正版免费的xshell和XFTP&#xff0c;并且还能够获得官网免费持久更新 白嫖步骤 首先直接在浏览器搜索xshell官网 点进官网之后直接点击下载 接着点击免费授权页面 进入之后就可以免费下载了 下载安装完成后填写用户名和邮箱并提交&#xff0c;这里就以xshell为…

Veritas NetBackup 10.5 发布,新增功能概览

Veritas NetBackup 10.5 发布&#xff0c;新增功能概览 Veritas NetBackup 10.5 (Unix, Linux, Windows) - 领先的企业备份解决方案 The #1 enterprise backup and recovery solution. 请访问原文链接&#xff1a;https://sysin.org/blog/veritas-netbackup-10/ 查看最新版。…

EditPlus的安装软件包

解压并粘贴到C:\Program Files (x86)中 点击激活密匙,并一直同意 确认并选择默认的位置: 关闭并重新激活密匙 就好了 无需添加快捷方式: 只需要选择任意文件 并选择该应用打开一次即可 通过百度网盘分享的文件&#xff1a;EditPlus_5.0.611.zip 链接&#xff1a;https://pa…