第 6 章:优化动态分配内存的变量_《C++性能优化指南》_notes

优化动态分配内存的变量

      • 第六章核心知识点详解
      • 总结
      • 第六章 动态内存优化 重点难点梳理
    • 一、多选题(每题至少2个正确答案)
    • 二、设计题
    • 答案与详解
      • 多选题答案
      • 设计题答案示例

第六章核心知识点详解

  1. 动态内存分配的开销
    知识点:动态内存分配需要调用操作系统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

分析:动态分配比栈分配慢百倍,需避免高频使用。


  1. 智能指针优化
    知识点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零开销,更高效。


  1. 避免不必要的复制
    知识点: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内容,性能显著提升。


  1. 返回值优化(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跳过了拷贝和移动构造,直接构造目标对象。


  1. 自定义内存分配器
    知识点:通过重载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)定位热点,针对性优化。

第六章 动态内存优化 重点难点梳理

核心知识点:

  1. 智能指针所有权管理(shared_ptr/unique_ptr)
  2. 减少动态内存分配策略(预分配、对象池)
  3. 移动语义与右值引用优化
  4. 自定义内存分配器实现
  5. 写时复制(Copy-on-Write)优化模式
  6. 扁平数据结构设计
  7. 内存碎片管理
  8. 线程安全的内存管理

一、多选题(每题至少2个正确答案)

  1. 关于shared_ptr线程安全性,正确的是:
    A) 引用计数是原子操作
    B) 指向的对象本身线程安全
    C) 多个线程写同一个shared_ptr需要同步
    D) make_shared比new更高效

  2. 哪些方法能有效减少动态内存分配?
    A) 使用内存池
    B) 优先使用栈分配
    C) 使用vector::reserve预分配
    D) 全局静态对象

  3. 移动语义的优势包括:
    A) 消除深拷贝开销
    B) 允许资源转移
    C) 保证异常安全
    D) 自动处理循环引用

  4. 实现高效内存分配器的关键点:
    A) 固定大小内存块管理
    B) 线程本地存储
    C) 内存对齐保证
    D) 使用系统malloc

  5. 关于写时复制(COW),正确的是:
    A) 修改时触发真实复制
    B) 适用于高频读取场景
    C) 需要引用计数
    D) C++11后推荐使用

  6. 扁平数据结构的优势:
    A) 更好的缓存局部性
    B) 减少间接指针
    C) 简化内存管理
    D) 支持快速插入

  7. 自定义内存分配器的应用场景:
    A) 高频小对象分配
    B) 实时系统
    C) 多线程环境
    D) 持久化存储

  8. 优化动态数组性能的方法:
    A) reserve预分配容量
    B) 使用emplace_back
    C) 避免中间临时对象
    D) 使用链表替代

  9. 移动构造函数应具备:
    A) noexcept声明
    B) 转移资源所有权
    C) 深拷贝实现
    D) 修改原对象状态

  10. 线程安全内存管理策略:
    A) 使用TLS分配器
    B) 全局互斥锁保护
    C) 无锁队列分配
    D) 静态内存池


二、设计题

  1. 实现线程安全的内存池
    要求:支持固定大小内存块的分配/释放,多线程环境下高效工作,提供性能对比测试

  2. 优化动态数组高频插入
    设计一个支持快速插入的优化版vector,避免频繁扩容,提供基准测试对比

  3. 移动语义优化矩阵运算
    实现矩阵类,使用移动语义优化矩阵运算返回值,消除临时对象复制

  4. 写时复制字符串优化
    实现COW字符串类,支持高效的拷贝和修改操作,测量性能提升

  5. 自定义STL分配器
    实现符合C++标准的固定大小内存分配器,与std::vector集成并测试性能


答案与详解

多选题答案

  1. ACD
    B错误:指向对象需自行保证线程安全
    D正确:make_shared合并内存分配

  2. ABC
    D错误:全局对象可能导致初始化顺序问题

  3. AB
    C错误:移动可能抛出异常
    D错误:无关循环引用

  4. ABC
    D错误:自定义分配器应避免直接调用malloc

  5. ABC
    D错误:C++11后移动语义更优

  6. ABC
    D错误:扁平结构插入效率低

  7. ABC
    D错误:持久化需要其他机制

  8. ABC
    D错误:链表缓存不友好

  9. ABD
    C错误:移动应转移而非深拷贝

  10. AC
    B错误:全局锁影响性能
    D错误:静态池灵活性差


设计题答案示例

  1. 线程安全内存池实现
#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";
}
  1. 优化版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";
}

其他设计题目, 稍后补充


测试验证要点:

  1. 编译命令:g++ -std=c++17 -O2 test.cpp -o test
  2. 内存泄漏检测:Valgrind工具检查
  3. 性能对比:至少3次测试取平均值
  4. 多线程测试:使用std::async创建并发任务

通过这些问题和实现,可以有效巩固动态内存优化的核心概念,并在实践中验证各种优化技术的实际效果。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vim的一般操作(分屏操作) 和 Makefile 和 gdb

目录 一. vim的基本概念 二. vim基础操作 2.1 插入模式 aio 2.2 [插入模式]切换至[正常模式] Esc 2.3[正常模式]切换至[末行模式] shift ; 2.4 替换模式 Shift R 2.5 视图&#xff08;可视&#xff09;模式 (可以快速 删除//注释 或者 增加//注释) ctrl v 三&…

NFC 智能门锁全栈解决方案:移动端、服务器、Web 管理平台

目录 一、系统整体架构 二、移动端 APP 开发 2.1 开发环境与基础准备 2.2 主要功能模块 2.3 示例代码&#xff08;Android/Kotlin 简化示例&#xff09; 三、后台服务开发 3.1 环境准备 3.2 主要功能 3.3 示例代码&#xff08;Node.js Express 简化示例&#xff09; …

系统与网络安全------网络应用基础(5)

资料整理于网络资料、书本资料、AI&#xff0c;仅供个人学习参考。 虚拟化 虚拟化技术原理概述虚拟化虚拟化实现条件常见的虚拟化软件产品 VMware应用实战安装VMware Workstation创建新虚拟机虚拟机的硬件配置调整 虚拟化高级应用虚拟机备份虚拟机快照 虚拟化技术 原理概述 虚…

Postman 下载文件指南:如何请求 Excel/PDF 文件?

在 Postman 中进行 Excel/PDF 文件的请求下载和导出&#xff0c;以下是简明的步骤&#xff0c;帮助你轻松完成任务。首先&#xff0c;我们将从新建接口开始&#xff0c;逐步引导你完成整个过程。 Postman 请求下载/导出 excel/pdf 文件教程

华为HCIE学习指南,如何更好的学习HCIE?

新盟教育 专注华为认证培训十余年 为你提供认证一线资讯&#xff01; 在竞争激烈的ICT行业&#xff0c;华为HCIE认证犹如一颗璀璨的明珠&#xff0c;散发着耀眼的光芒。它不仅是对个人技术能力的高度认可&#xff0c;更是开启高薪职业大门的钥匙。然而&#xff0c;华为HCIE学习…

贪心算法——c#

贪心算法通俗解释 贪心算法是一种"每一步都选择当前最优解"的算法策略。它不关心全局是否最优&#xff0c;而是通过局部最优的累积来逼近最终解。优点是简单高效&#xff0c;缺点是可能无法得到全局最优解。 一句话秒懂 自动售货机找零钱&#xff1a;用最少数量的…

架构思维:如何设计一个支持海量数据存储的高扩展性架构_数据分片、存储、复制与一致性的原理性问题

文章目录 PRE引言1. 数据分片策略Hash取模分片一致性Hash分片Range分片分片设计原理核心设计模块分片规则定义动态分片调整路由与负载均衡 应对热点的关键技术多级分片&#xff08;Hierarchical Sharding&#xff09;副本分散策略缓存层配合 典型应用场景优缺点分析 2. 应对热点…

Jenkins最新版,配置Gitee私人令牌和Gitee凭证

jenkins 配置Gitee私人令牌和凭证 jenkins 版本&#xff1a;Jenkins 2.492.2 Gitee配置 Jenkins配置gitee插件&#xff0c;需要先申请gitee私钥。 安装gitee插件 申请Gitee私人令牌&#xff0c;后面还需要添加凭证。 测试链接&#xff0c;并保存 配置凭证

ORACLE RAC ASM双存储架构下存储部分LUN异常的处理

早上接到用户电话&#xff0c;出现有表空间不足的告警&#xff0c;事实上此环境经常巡检并且有告警系统&#xff0c;一开始就带着有所疑惑的心理&#xff0c;结果同事在扩大表空间时&#xff0c;遇到报错 ORA-15401/ORA-17505,提示ASM空间满了&#xff1a; ALERT日志&#xff1…

Windows下docker使用教程

docker安装 镜像制作镜像加载容器创建更新镜像导出镜像 Windows10安装dockerdocker image制作docker 镜像加载docker 容器创建更新imageimage 导出为.tar文件 #以Windows10 、11为例 linux和Windows区别在于docker安装的程序是哪个操作系统的&#xff0c;后面的内容其实不变 …

9.4分漏洞!Next.js Middleware鉴权绕过漏洞安全风险通告

今日&#xff0c;亚信安全CERT监控到安全社区研究人员发布安全通告&#xff0c;Next.js 存在一个授权绕过漏洞&#xff0c;编号为 CVE-2025-29927。攻击者可能通过发送精心构造的 x-middleware-subrequest 请求头绕过中间件安全控制&#xff0c;从而在未授权的情况下访问受保护…

代码随想录算法训练营Day12 | Leetcode 226翻转二叉树、101对称二叉树、104二叉树的最大深度、111二叉树的最小深度

代码随想录算法训练营Day12 | Leetcode 226翻转二叉树、101对称二叉树、104二叉树的最大深度、111二叉树的最小深度 一、翻转二叉树 相关题目&#xff1a;Leetcode226 文档讲解&#xff1a;Leetcode226 视频讲解&#xff1a;Leetcode226 1. Leetcode226.翻转二叉树 给你一棵二…

3.26学习总结 做题

先初始化n1时&#xff0c;输出的图案。 观察可以得到&#xff0c;n每加1&#xff0c;则在原先图案的左下方和右下方重新打印一遍原先的图案&#xff0c;可以分为两步。 1.复制原先图案打印在其正下方和右下方&#xff0c;并将原先图案清空。 2.在现在图案的上方中间打印原先…

Linux学习笔记(应用篇二)

基于I.MX6ULL.MINI开发板 开发板与电脑相互通信电脑与开发板互传文件 开发板与电脑相互通信 用网线将电脑与开发板连接 本人使用的是Ubuntu系统&#xff0c;不是虚拟机 一般来说刚开始电脑和开发板是ping不通的 首先查看电脑的 IP WinR&#xff0c;cmd调出终端 我使用的是…

【gradio】从零搭建知识库问答系统-Gradio+Ollama+Qwen2.5实现全流程

从零搭建大模型问答系统-GradioOllamaQwen2.5实现全流程&#xff08;一&#xff09; 前言一、界面设计&#xff08;计划&#xff09;二、模块设计1.登录模块2.注册模块3. 主界面模块4. 历史记录模块 三、相应的接口&#xff08;前后端交互&#xff09;四、实现前端界面的设计co…

中间件漏洞-Tomcat篇

一&#xff1a;CVE-2017-12615 1.搭建服务 cd /www/wwwroot/vulhub-master/tomcat/CVE-2017-12615 docker-compose up -d 2.打开网页 3.在哥斯拉中生成jsp木马并保存为2.jpg 对当前页面进行抓包&#xff0c;修改提交方式为PUT并复制木马 4.在网页中访问我们生成的木马&#…

PHP eval 长度限制绕过与 Webshell 获取

在 PHP 代码中&#xff0c;如果 eval($param); 存在且长度受限&#xff0c;并且过滤了 eval 和 assert&#xff0c;仍然可以通过多种方法绕过限制&#xff0c;获取 Webshell。 源码 <?php $param $_REQUEST[param]; if(strlen($param)<17 && stripos($param,…

31天Python入门——第15天:日志记录

你好&#xff0c;我是安然无虞。 文章目录 日志记录python的日志记录模块创建日志处理程序并配置输出格式将日志内容输出到控制台将日志写入到文件 logging更简单的一种使用方式 日志记录 日志记录是一种重要的应用程序开发和维护技术, 它用于记录应用程序运行时的关键信息和…

特殊行车记录仪DAT视频丢失的恢复方法

行车记录仪是一种常见的车载记录仪&#xff0c;和常见的“小巧玲珑”的行车记录仪不同&#xff0c;一些特种车辆使用的记录仪的外观可以用“笨重”来形容。下边我们来看看特种车载行车记录仪删除文件后的恢复方法。 故障存储: 120GB存储设备/文件系统:exFAT /簇大小:128KB 故…

机器学习——KNN数据均一化

在KNN&#xff08;K-近邻&#xff09;算法中&#xff0c;数据均一化&#xff08;归一化&#xff09;是预处理的关键步骤&#xff0c;用于消除不同特征量纲差异对距离计算的影响。以下是两种常用的归一化操作及其核心要点&#xff1a; 质押 一 、主要思想 1. 最值归一化&#…