第 6 章:优化动态分配内存的变量_《C++性能优化指南》_notes
优化动态分配内存的变量
- 第六章核心知识点详解
- 总结
- 第六章 动态内存优化 重点难点梳理
- 一、多选题(每题至少2个正确答案)
- 二、设计题
- 答案与详解
- 多选题答案
- 设计题答案示例
第六章核心知识点详解
- 动态内存分配的开销
知识点:动态内存分配需要调用操作系统API,涉及锁竞争和内存碎片,频繁分配释放会导致性能瓶颈。
代码示例(比较动态数组 vs 静态数组):
#include <iostream>
#include <vector>
#include <chrono>void test_dynamic_allocation() {auto start = std::chrono::high_resolution_clock::now();for (int i=0; i<100000; ++i) {int* arr = new int[100]; // 频繁动态分配delete[] arr;}auto end = std::chrono::high_resolution_clock::now();std::cout << "Dynamic: " << std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count() << " ms\n";
}void test_static_allocation() {auto start = std::chrono::high_resolution_clock::now();for (int i=0; i<100000; ++i) {int arr[100]; // 栈上分配,快速}auto end = std::chrono::high_resolution_clock::now();std::cout << "Static: " << std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count() << " ms\n";
}int main() {test_dynamic_allocation();test_static_allocation();return 0;
}
输出:
Dynamic: 120 ms
Static: 0 ms
分析:动态分配比栈分配慢百倍,需避免高频使用。
- 智能指针优化
知识点:std::shared_ptr引用计数有性能损耗,优先使用std::unique_ptr。
代码示例:
#include <memory>
#include <iostream>struct Widget {Widget() { std::cout << "Widget created\n"; }~Widget() { std::cout << "Widget destroyed\n"; }
};void use_shared() {auto ptr = std::make_shared<Widget>(); // 引用计数+1auto ptr2 = ptr; // 引用计数+1
}void use_unique() {auto ptr = std::make_unique<Widget>(); // 独占所有权// auto ptr2 = ptr; // 错误!无法复制unique_ptr
}int main() {std::cout << "Shared ptr:\n";use_shared();std::cout << "Unique ptr:\n";use_unique();
}
输出:
Shared ptr:
Widget created
Widget destroyed
Unique ptr:
Widget created
Widget destroyed
分析:shared_ptr适合共享所有权,但引用计数带来开销;unique_ptr零开销,更高效。
- 避免不必要的复制
知识点:C++11引入移动语义,通过std::move转移资源,避免深拷贝。
代码示例:
#include <vector>
#include <iostream>class HeavyData {std::vector<int> data;
public:HeavyData(size_t size) : data(size, 42) {std::cout << "HeavyData constructed\n";}// 移动构造函数HeavyData(HeavyData&& other) noexcept : data(std::move(other.data)) {std::cout << "HeavyData moved\n";}// 移动赋值运算符HeavyData& operator=(HeavyData&& other) noexcept {data = std::move(other.data);std::cout << "HeavyData moved assigned\n";return *this;}
};int main() {HeavyData a(1000);HeavyData b = std::move(a); // 调用移动构造HeavyData c(2000);c = std::move(b); // 调用移动赋值return 0;
}
输出:
HeavyData constructed
HeavyData moved
HeavyData constructed
HeavyData moved assigned
分析:移动操作避免了复制vector内容,性能显著提升。
- 返回值优化(RVO)
知识点:编译器优化,消除函数返回时的临时对象复制。
代码示例:
#include <iostream>struct Data {Data() { std::cout << "Data created\n"; }Data(const Data&) { std::cout << "Data copied\n"; }Data(Data&&) { std::cout << "Data moved\n"; }
};Data createData() {return Data(); // 可能触发RVO
}int main() {Data d = createData();return 0;
}
输出(启用RVO时):
Data created
分析:RVO跳过了拷贝和移动构造,直接构造目标对象。
- 自定义内存分配器
知识点:通过重载new/delete或使用内存池减少分配开销。
代码示例(简单内存池):
#include <iostream>
#include <vector>class MemoryPool {std::vector<void*> blocks;
public:void* allocate(size_t size) {void* block = ::operator new(size);blocks.push_back(block);return block;}~MemoryPool() {for (auto p : blocks) ::operator delete(p);}
};struct FastObject {static MemoryPool pool;void* operator new(size_t size) {return pool.allocate(size);}void operator delete(void* p) {// 内存池统一释放}
};MemoryPool FastObject::pool;int main() {FastObject* obj = new FastObject;delete obj;return 0;
}
分析:集中管理内存分配,减少碎片和系统调用次数。
总结
第六章的核心在于减少动态内存操作,优先使用栈对象和移动语义,合理选择智能指针,利用编译器优化如RVO。每个优化点都有对应的代码实践,通过测量性能差异可验证优化效果。实际项目中需结合性能分析工具(如Valgrind、perf)定位热点,针对性优化。
第六章 动态内存优化 重点难点梳理
核心知识点:
- 智能指针所有权管理(shared_ptr/unique_ptr)
- 减少动态内存分配策略(预分配、对象池)
- 移动语义与右值引用优化
- 自定义内存分配器实现
- 写时复制(Copy-on-Write)优化模式
- 扁平数据结构设计
- 内存碎片管理
- 线程安全的内存管理
一、多选题(每题至少2个正确答案)
-
关于shared_ptr线程安全性,正确的是:
A) 引用计数是原子操作
B) 指向的对象本身线程安全
C) 多个线程写同一个shared_ptr需要同步
D) make_shared比new更高效 -
哪些方法能有效减少动态内存分配?
A) 使用内存池
B) 优先使用栈分配
C) 使用vector::reserve预分配
D) 全局静态对象 -
移动语义的优势包括:
A) 消除深拷贝开销
B) 允许资源转移
C) 保证异常安全
D) 自动处理循环引用 -
实现高效内存分配器的关键点:
A) 固定大小内存块管理
B) 线程本地存储
C) 内存对齐保证
D) 使用系统malloc -
关于写时复制(COW),正确的是:
A) 修改时触发真实复制
B) 适用于高频读取场景
C) 需要引用计数
D) C++11后推荐使用 -
扁平数据结构的优势:
A) 更好的缓存局部性
B) 减少间接指针
C) 简化内存管理
D) 支持快速插入 -
自定义内存分配器的应用场景:
A) 高频小对象分配
B) 实时系统
C) 多线程环境
D) 持久化存储 -
优化动态数组性能的方法:
A) reserve预分配容量
B) 使用emplace_back
C) 避免中间临时对象
D) 使用链表替代 -
移动构造函数应具备:
A) noexcept声明
B) 转移资源所有权
C) 深拷贝实现
D) 修改原对象状态 -
线程安全内存管理策略:
A) 使用TLS分配器
B) 全局互斥锁保护
C) 无锁队列分配
D) 静态内存池
二、设计题
-
实现线程安全的内存池
要求:支持固定大小内存块的分配/释放,多线程环境下高效工作,提供性能对比测试 -
优化动态数组高频插入
设计一个支持快速插入的优化版vector,避免频繁扩容,提供基准测试对比 -
移动语义优化矩阵运算
实现矩阵类,使用移动语义优化矩阵运算返回值,消除临时对象复制 -
写时复制字符串优化
实现COW字符串类,支持高效的拷贝和修改操作,测量性能提升 -
自定义STL分配器
实现符合C++标准的固定大小内存分配器,与std::vector集成并测试性能
答案与详解
多选题答案
-
ACD
B错误:指向对象需自行保证线程安全
D正确:make_shared合并内存分配 -
ABC
D错误:全局对象可能导致初始化顺序问题 -
AB
C错误:移动可能抛出异常
D错误:无关循环引用 -
ABC
D错误:自定义分配器应避免直接调用malloc -
ABC
D错误:C++11后移动语义更优 -
ABC
D错误:扁平结构插入效率低 -
ABC
D错误:持久化需要其他机制 -
ABC
D错误:链表缓存不友好 -
ABD
C错误:移动应转移而非深拷贝 -
AC
B错误:全局锁影响性能
D错误:静态池灵活性差
设计题答案示例
- 线程安全内存池实现
#include <iostream>
#include <vector>
#include <memory>
#include <mutex>
#include <chrono>template <size_t BlockSize, size_t PoolSize>
class ThreadSafeMemoryPool {
public:ThreadSafeMemoryPool() {for (int i = 0; i < PoolSize; ++i) {free_blocks.push(new char[BlockSize]);}}void* allocate() {std::lock_guard<std::mutex> lock(mtx);if (free_blocks.empty()) {return ::operator new(BlockSize);}void* block = free_blocks.top();free_blocks.pop();return block;}void deallocate(void* block) {std::lock_guard<std::mutex> lock(mtx);free_blocks.push(static_cast<char*>(block));}~ThreadSafeMemoryPool() {while (!free_blocks.empty()) {delete[] free_blocks.top();free_blocks.pop();}}private:std::mutex mtx;std::stack<char*> free_blocks;
};// 测试用例
int main() {constexpr size_t TEST_SIZE = 1000000;ThreadSafeMemoryPool<64, 1000> pool;auto start = std::chrono::high_resolution_clock::now();for (int i = 0; i < TEST_SIZE; ++i) {void* p = pool.allocate();pool.deallocate(p);}auto end = std::chrono::high_resolution_clock::now();std::cout << "Pool time: " << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count()<< "μs\n";// 对比系统mallocstart = std::chrono::high_resolution_clock::now();for (int i = 0; i < TEST_SIZE; ++i) {void* p = malloc(64);free(p);}end = std::chrono::high_resolution_clock::now();std::cout << "Malloc time: " << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count()<< "μs\n";
}
- 优化版Vector设计
template <typename T>
class OptimizedVector {
public:OptimizedVector() : capacity_(4), size_(0) {data_ = static_cast<T*>(::operator new(capacity_ * sizeof(T)));}void push_back(T&& value) {if (size_ >= capacity_) {reserve(capacity_ * 2);}new (&data_[size_]) T(std::move(value));++size_;}void reserve(size_t new_cap) {if (new_cap <= capacity_) return;T* new_data = static_cast<T*>(::operator new(new_cap * sizeof(T)));for (size_t i = 0; i < size_; ++i) {new (&new_data[i]) T(std::move(data_[i]));data_[i].~T();}::operator delete(data_);data_ = new_data;capacity_ = new_cap;}// ...其他接口private:T* data_;size_t capacity_;size_t size_;
};// 测试用例
int main() {OptimizedVector<std::string> vec;constexpr int TEST_SIZE = 1000000;auto start = std::chrono::high_resolution_clock::now();for (int i = 0; i < TEST_SIZE; ++i) {vec.push_back(std::string(100, 'a'));}auto end = std::chrono::high_resolution_clock::now();std::cout << "Optimized vector: "<< std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()<< "ms\n";// 对比std::vectorstd::vector<std::string> std_vec;start = std::chrono::high_resolution_clock::now();for (int i = 0; i < TEST_SIZE; ++i) {std_vec.emplace_back(100, 'a');}end = std::chrono::high_resolution_clock::now();std::cout << "std::vector: "<< std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()<< "ms\n";
}
其他设计题目, 稍后补充
测试验证要点:
- 编译命令:
g++ -std=c++17 -O2 test.cpp -o test - 内存泄漏检测:Valgrind工具检查
- 性能对比:至少3次测试取平均值
- 多线程测试:使用std::async创建并发任务
通过这些问题和实现,可以有效巩固动态内存优化的核心概念,并在实践中验证各种优化技术的实际效果。
相关文章:
第 6 章:优化动态分配内存的变量_《C++性能优化指南》_notes
优化动态分配内存的变量 第六章核心知识点详解总结第六章 动态内存优化 重点难点梳理 一、多选题(每题至少2个正确答案)二、设计题答案与详解多选题答案设计题答案示例 第六章核心知识点详解 动态内存分配的开销 知识点:动态内存分配需要调用…...
k8s kubernetes dashboard一直CarshLoopBackoff
使用 kubectl get pods -A -o wide 发现pod一直CarshLoopBackoff 通过 kubectl describe pod kubernetes-dashboard-7c4f8ff86d-7k7bd -n kubernetes-dashboard 获取详细信息 发现一直报错 Warning Unhealthy 10m (x31 over 34m) kubelet Liveness probe fail…...
[C++面试] 你了解视图吗?
一、入门 1、什么是 C 视图(View)?请简要说明其概念和用途 它提供了对序列(如数组、容器等)的非拥有性、只读或可写的访问。(就像是个透明的放大镜,它能让你去看一组数据,但它自己…...
Vue3 项目通过 docxtemplater 插件动态渲染 .docx 文档(带图片)预览,并导出
Vue3 项目通过 docxtemplater 插件动态渲染 .docx 文档(带图片)预览,并导出 预览安装插件示例代码项目目录结构截图实际效果截图 动态渲染 .docx 文档(带图片),预览、导出安装插件docx 模板文件内容完整代码…...
ollama迁移已下载的单个模型到服务器
ollama迁移已下载的单个模型到服务器 场景 ollama是面向用户级的,部署和运行都很简单,是否高效就另说了。但最起码,他能充分利用用户的硬件设备,在GPU不足也能调用cpu和内存去加持。 ollama运行的模型基本是量化版本的…...
Photoshop 2025安装教程包含下载安装包,2025最新版图文安装教程
文章目录 前言一、Photoshop 2025下载二、Photoshop 2025安装教程1. 安装包解压2. 找到安装程序3. 以管理员身份运行4. 安装选项设置5. 选择安装路径6. 开始安装7. 安装完成8. 启动软件9. 软件主界面 前言 无论你是专业设计师,还是刚接触图像处理的新手,…...
【Python · PyTorch】时域卷积网络 TCN
1. 概念 1.1 定义 TCN 是时域卷积网络(Temporal Convolutional Network)的简称。TCN是于2018年 Shaojie Bai 等人提出的一个处理时序数据的卷积模型。 TCN结合了CNN卷积并行性计算和RNN长期依赖的优势,CNN可在多个通道同时处理卷积核运算&…...
Mysql update更新数据执行流程
update 的执行流程是以select查询为基础执行的!!你不明白select执行流程?没关系,这篇博客照样让你明白,update执行流程! 存储引擎是什么? 如果把数据库比作一个大仓库,那么存储引擎…...
WMS WCS系统架构
1.1立体仓库现场网络架构图 1.2立体仓库WMS系统与WCS系统架构 1.3系统技术选型 WEB端技术:node.js、vue 、element、jquery、html、js、css等 API端技术:spring boot 、msyql、redis、mybatis等 WCS技术:c#、winform、OPC、socket、S7等 …...
数据结构5(初):续写排序
目录 1、外排序 2、计数排序 1、外排序 上一节中提到的排序都可以用来进行内排序,但是只有归并排序的思想可以用来进行外部排序,因为文件数据是没办法像数组那样进行访问的。 例如: #include <stdio.h> #include <assert.h> …...
ROS多机通信(三)——Ubuntu Ad-Hoc 组网通信配置指南
基本概念 Ad-Hoc 网络是一种简单的点对点无线网络,设备(称为节点)可以直接相互通信或者通过中继间接通信,而无需依赖中央接入点。在这种网络中,所有设备是对等的,没有固定的路由器或基础设施支持。 特点 …...
23种设计模式-状态(State)设计模式
状态设计模式 🚩什么是状态设计模式?🚩状态设计模式的特点🚩状态设计模式的结构🚩状态设计模式的优缺点🚩状态设计模式的Java实现🚩代码总结🚩总结 🚩什么是状态设计模式…...
ARM架构薄记2——ARM学习架构抓手(以ARMv7为例子)
ARM架构薄记2——ARM学习架构抓手(以ARMv7为例子) 架构学习需要学习哪一些部分呢?笔者接触过的架构有Intel-X86, AMD64,RISC-V和Arm架构(V7最多),笔者简单的翻了一些课本和教材,…...
STM32C011 进入停止模式和待机模式
对于STM32C011J4M3微控制器,你可以使用HAL库来实现进入停止模式(Stop Mode)和待机模式(Standby Mode)。下面是进入停止模式和待机模式的示例代码: 进入停止模式代码示例: #include "stm3…...
kaggle上经典泰坦尼克项目数据分析探索
之前了解在kaggle上这个项目很火,最近想要加强一下python数据分析,所以在kaggle上找到这个项目进行学习探索,下面是将一些学习资料以及过程整理出来。 一、首先我们了解一下项目背景以及如何找到这个项目。 kaggle项目地址: https://www.k…...
影刀魔法指令3.0:开启自动化新篇章
在数字化飞速发展的今天,自动化工具已经成为提升工作效率、优化工作流程的重要手段。影刀RPA作为一款强大的自动化软件,其最近推出的魔法指令3.0版本,更是让人大开眼界,为自动化操作带来了全新的可能性。 影刀魔法指令3.0简介 影…...
15 python 数据容器-字典
在 Python 的编程世界里,字典是一种超实用的数据类型,它就像打工人的工作资料夹,能把各种不同类型的信息有条理地存起来,还能快速找到你需要的内容。对于刚开始学习编程的小伙伴来说,掌握字典的用法,能让你…...
Linux的一些常见指令
一、ls指令 语法: ls (选项) 功能: ls可以查看当前目录下的所有文件和目录。 常用选项: -a:列出目录下的所有文件,包括以点(.)开头的隐含文件 。-d:将目录像文件一样显示,不显示其下的文件。…...
Pre-flash和Main flash
在相机拍照过程中,Pre-flash(预闪光) 和 Main flash(主闪光) 是常见的两种闪光灯使用模式,通常用于提高低光环境下的拍摄质量,尤其在自动曝光(AE)和自动对焦(…...
jmm-java内存模型
java内存模型----底层原理 底层原理 从Java代码到最终执行的CPU指令的流程: 最开始,我们编写的Java代码,是*.java文件在编译(javac命令)后,从刚才的*.java文件会变出一个新的Java字节码文件(…...
合宙780E开发学习-LUATOS-SOC云编译自定义固件
登录https://luatos.com 点击登录,使用合宙erp账号登录即可 点击右上角构建,点击右上角菜单新构建,自定义构建名称,可新建多个 勾选想要的组件 点击右上角保存修改,只有点击准备就绪(注意:一定…...
解决Centos使用yum命令报错“Cannot find a valid baseurl for repo: base/7/x86_64”问题
一、问题描述 我们在使用Centos7.9使用【sudo yum install influxdb2】命令安装influxDB数据库的时候提示“Loading mirror speeds from cached hostfile Could not retrieve mirrorlist http://mirrorlist.centos.org/release=7&arch=x86_64&repo=os&infra=stock …...
好用的Markdown阅读编辑器Typora破解记录
Typora破解 一、下载Typora二、安装Typora三、破解Typora 😀 记录一下Typora破解记录,怕不常用忘记咯,感觉自己现在的脑子就像我的肠子一样,刚装进去就么得了。。。😔 Typroa算是用起来很舒服的Markdown阅读器了吧&am…...
c#在work线程中怎样更新UI控件
最近笔者调试修改项目,碰到了c#在work线程中怎样更新UI控件中的场景,简单总结了下,主要有两个方法: 方法1:通过System.Windows.Application.Current.Dispatcher.Invoke来更新UI控件 System.Windows.Application.Curre…...
RabbitMQ三种队列深度解析:区别、场景与未来趋势
嗯,用户让我分析RabbitMQ三种队列的区别、应用场景、技术原理和未来趋势,还要写一篇三千字的文章。首先,我需要回顾一下搜索结果,看看有哪些资料可用。 根据搜索结果,RabbitMQ的三种队列是经典队列(Classi…...
自然语言处理(13:RNN的实现)
系列文章目录 第一章 1:同义词词典和基于计数方法语料库预处理 第一章 2:基于计数方法的分布式表示和假设,共现矩阵,向量相似度 第一章 3:基于计数方法的改进以及总结 第二章 1:word2vec 第二章 2:word2vec和CBOW模型的初步实现 第二章 3:CBOW模型…...
WebSocket接入SSL证书
目录 碎碎念解决方法创建 HTTPS WebSocket 服务器创建系统服务启动服务 碎碎念 在访问网站时,使用 HTTPS 非常重要。HTTPS 协议不仅可以确保数据传输的安全性,还可以防止中间人攻击和数据篡改等安全问题。任何没有 SSL 证书的内容都可能会被拒绝访问。因…...
无人机宽带自组网机载电台技术详解,50KM超远图数传输系统实现详解
以下是关于无人机宽带自组网机载电台技术以及50KM超远图数传输系统实现的详解: 无人机宽带自组网机载电台技术详解 无人机宽带自组网机载电台是一种专门为无人机设计的通信设备,它支持宽带数据传输和自组网功能。这种电台的实现技术涉及多个方面&#x…...
MySQL 表 t1 建立联合索引 (a, b, c),在 where a < ? and b > ? and c < ? 中哪些索引生效
文章目录 联合索引 abc 均范围扫描时的索引生效情况无回表 表数据量非常少无回表 表数据量多有回表总结 联合索引 abc 均范围扫描时的索引生效情况 场景:表 t1 建立联合索引 (a, b, c),在 where a < ? and b > ? and c < ? 中哪些索引生效…...
Spring Boot定时任务设置与实现
Spring Boot定时任务设置与实现 在Spring Boot中,可以使用Scheduled注解来创建定时任务。以下是一个简单的示例,展示了如何在项目启动后每5秒调用一次指定的方法。 1. 添加依赖 首先,确保你的pom.xml文件中包含Spring Boot的依赖ÿ…...
