C++性能优化常用技巧
一. 选择合适的数据结构
1.1 map与unordered_map的选择
如果仅仅只需要使用到快速查找的特性,那么unordered_map更加合适,他的复杂度是O(1)。如果还需要排序以及范围查找的能力,那么就选择map。
1.2 vector与list的选择
通常情况下,顺寻存储一些数据,然后通过下标进行查找,就选择vector。那么什么时候选择list呢?常见的一个用法就是在LRU 缓存的实现中,我们会使用list来存放缓存结点,而不是vector,主要原因就在于list的插入和删除是高效的。
1.3 unordered_map与自定义查找表的选择
如果不需要复杂的哈希函数,仅通过数组下标的形式就能完成哈希,比如key是26个字母或者连续的数字。此时只需要定义一个数组就能实现哈希存储(自定义查找表)。
二. 选择合适的算法
算法对性能的影响是值得考虑的,以排序算法举例:
- 快速排序:适合数据比较均匀的场景,如果数据已经有序或者接近有序,此时快速排序会退化到O(n*n)的复杂度。
- 堆排序:适合求topK问题。
- 归并排序:O(n)的空间复杂度,但是排序性能不会因为数据本身已经有序而退化。
- 冒泡排序:一般情况下不推荐此排序。性能较差。
三. 避免不必要的拷贝
3.1 使用引用
引用可以直接与被引用对象共享同一份存储,可以认为引用是给对象起一个别名。如下示例代码:
// 形参使用引用
void show(const std::string& str)
{// do something
}std::vector<std::string> strs;
/*
对strs进行填充
*/
// 使用引用接收返回值,前提是函数返回对象的引用
const std::string& str = strs[1];
3.2 使用移动语义
移动语义一般用在初始化对象或者给对象赋值时,可以避免对象的拷贝。如下代码:
std::string stra = "abc";
// 拷贝stra对象
std::string strb = stra;
// 移动strb的资源到strc中
std::string strc = std::move(strb);
3.3 返回值优化(RVO)
通常编译器都有RVO优化的功能,它允许直接在调用者的栈帧上构造对象,从而避免了额外的拷贝和资源析构的开销。如下代码:
class A {
public:A() {}~A() {}A(const A& rhs) {}A(A&& rhs) {}
};int func()
{A a;return a;
}int main()
{A a = func();return 0;
}
上述代码中,返回值优化之后,类A的构造函数和析构函数只被调用一次,不会产生临时变量的构造与析构,以及拷贝构造的过程。
四. 合适的内存管理
4.1 智能指针
在管理动态内存时,智能指针可以帮助我们实现更可靠的内存管理,避免内存泄漏等严重问题。C++11中提供了unique_ptr和shared_ptr两个智能指针,那么该如何选择呢?
- shared_ptr:共享智能指针。一个对象可能在多个地方被共享。
- unique_ptr:独占智能指针。一个对象只能被一个智能指针对象所拥有。
通常情况下,如果能明确是独占的场景,那么就选择unique_ptr,虽然shared_ptr也能保证正确性,但是后者性能要比前者差30%。因为uniqe_ptr更接近裸指针,而shared_ptr内部实现相对复杂(引用计数、控制块等)。
4.2 内存池
内存池是一个预先申请和分配好的内存区域。在需要申请内存资源时,可以直接在内存池中获取,在释放内存时,将内存返还给内存池。从而避免了频繁的内存分配和释放的过程。google的tcmalloc就提供了这样的功能。
4.3 对象池
对象池同样也是一种预先申请和分配内存的技术,区别于内存池的是,其针对的是特定的类对象的内存管理。如果一个类型需要频繁的进行对象的创建和释放,并且对象的创建比较耗时。那么我们可以选择使用池化技术,预先创建好一定数量的对象,放到对象池中。其实很多池化技术都属于这个范畴,只是针对不同场景,有其独特的叫法,如MySQL的连接池、线程池等等。
4.4 栈内存的管理
通常我们只需要管理堆内存,而栈内存交给操作系统来管理。但是栈内存的申请和初始化依旧是由程序员来控制的,而操作系统只负责内存的分配和释放。考虑如下场景:
void func()
{for (int i = 0; i < 999999; ++i) {char data[1000000];// do something}
}
上述data在每一次循环都需要分配一次内存,然后对其进行操作。如果data的创建可以放到循环体之外进行也不影响程序的正确性。那么data的内存分配只需要一次即可。
事实上,我们还可以继续优化。因为这块内存很大,函数也可能会被频繁调用,每次调用都会重复申请一大块内存。所以考虑创建一个静态的data变量,或者静态的全局变量。只要它能满足程序的正确性要求。何乐而不为呢?当然静态变量在多线程环境下会存在数据竞争的问题。此时还可以考虑使用threadlocal变量。
五、减少函数调用
5.1 使用内联函数
一次函数调用涉及两次指令跳转。如果一个函数频繁调用,可以使用内联机制来避免函数的调用。C++11提供了inline关键字,来告诉编译器被修饰的函数可以在调用处进行替换。一般这样的函数是一些功能简单,代码行较少的函数。当然是否内联取决于编译器,inline只是给编译器建议。是否内联可通过查看汇编代码来确认。
5.2 减少函数递归调用
函数递归通常写起来比较方便,并且也更好理解。但是函数递归带来的开销是巨大的,随着递归深度的加深,性能也会受到影响。稍有不慎,甚至会造成栈溢出。所以应该尽量避免使用递归函数,考虑使用迭代或者只使用尾递归(编译器优化,只需要当前的栈帧空间,无需开辟新空间)的方式。
六、多线程处理
多线程可以利用多核特性,同时处理多个任务,从而提高程序性能。多线程常常涉及数据竞争的问题,为了提高多线程的性能,应减少数据竞争,常见的方法有:
- 使用原子变量。
- 使用读写锁。
- 降低锁的持有时间。
- 使用线程池模型,重复利用线程资源,利用多队列减少工作线程间的数据竞争。
- 使用无锁数据结构,避免频繁的线程上下文切换。
- 减少需要共享的状态。
七、编译器优化
在考虑性能问题之前,首先得开启编译器优化,很多时候,代码虽然写的不是最优的,但是在开启编译优化之后,往往能达到很好的优化效果。常见的优化选项:
- O0:不做任何优化。
- O1:主要对代码的分支,常量以及表达式等进行优化。
- O2:会尝试更多的寄存器级的优化以及指令级的优化。
- O3:在O2的基础上进行更多的函数内联优化,因此目标代码会更大,但执行速度会更快。
八、指令级优化
8.1 SIMD指令
SIMD(单指令多数据)指的是具有多个处理元件的计算机同时对多个数据执行相同操作的过程。以加法为例,通常情况下,我们需要先取操作数1,再取操作数2,然后求和。而SIMD指令则支持同时取多个操作数,然后执行求和运算。也就是说取操作数的过程是并行的。在gcc中可以通过添加ftree-vectorize编译选项,或者开启O2优化,就可以让编译器使用SIMD优化代码。
九、提高缓存命中率
CPU有3级缓存L1、L2、L3,其中L1离核心最近,因此速度也最快。由于缓存有大小限制,因此只有少量的数据和指令会被加载到缓存中,所以经常会出现缓存无法命中的问题。因此提高cache命中率就可以提高程序性能。
9.1 选择合适的数据结构
数据结构多使用连续的存储,如vector,而少使用list、map这种非连续存储类型。因为连续的内存通常会被一起加载到缓存中。
9.2 内存对齐
内存不对齐的情况下,cpu可能需要夸多个内存行去获取数据。从而增加了cpu的访存次数,也增加了缓存不命中的可能性。
9.3 减少条件分支
程序中的条件判断,如 if-else 语句,可以通过逻辑重组或使用分支预测优化来提高缓存命中率。在某些情况下,消除不必要的条件判断或将其重构为更高效的形式可以减少缓存行的加载和卸载,从而提高性能。例如,使用gcc的提供的关键字__builtin_expect来告诉编译器哪个分支命中的概率最高,从而实现优化。
9.4 其他
- 避免频繁的内存分配与释放,减少内存碎片。
- 循环展开,减少循环次数。
- 循环中按行处理数据要比按列处理更高效。
相关文章:
C++性能优化常用技巧
一. 选择合适的数据结构 1.1 map与unordered_map的选择 如果仅仅只需要使用到快速查找的特性,那么unordered_map更加合适,他的复杂度是O(1)。如果还需要排序以及范围查找的能力,那么就选择map。 1.2 vector与list的选择 通常情况下&#…...
IntelliJ IDEA集成MarsCode AI
IntelliJ IDEA集成MarsCode AI IDEA中安装插件 安装完毕之后登录自己的账号 点击链接,注册账号 https://www.marscode.cn/events/s/i5DRGqqo/ 可以选择不同的模型...
数据挖掘工程师的技术图谱和学习路径
数据挖掘工程师的技术图谱和学习路径: 1.基础知识 数据挖掘工程师是负责从大量数据中发现潜在模式、趋势和规律的专业人士。以下是数据挖掘工程师需要掌握的基础知识: 数据库知识:熟悉关系数据库和非关系数据库的基本概念和操作,掌握SQL语言。 统计学基础:了解统计学的基…...
Excel基础(详细篇):总结易忽视的知识点,有用的细节操作
目录 基础篇Excel主要功能必会快捷键LotusExcel的文件类型工作表基本操作表项操作选中与缩放边框线 自动添加边框线格式刷设置斜线表头双/多斜线表头不变形的:双/多斜线表头插入多行、多列单元格/行列的移动冻结窗口 方便查看数据打印的常见问题Excel格式数字格式日期格式文本…...
基因枷锁下的太空梦 —— 千钧一发电影观后感
目录 1 人物介绍 2 电影名解读 3 电影开头 3.1 电影开头的两段话 3.2 片头设计 4 电影正文 4.1 “杰罗米”各种诡异的行为 4.2 文森特 – 失败的man 4.3 真正的杰罗米以及假基因身份证 4.4 文森特新征程 4.5 基因人的不容易 4.6 睫毛被查出有问题 4.7 文森特身份初…...
leetcode第40题组合总和Ⅱ
原题出于leetcode第40题https://leetcode.cn/problems/combination-sum-ii/题目如下: 给定一个候选人编号的集合 candidates (candidate中有重复的元素)和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合…...
迷你世界脚本状态接口:Buff
状态接口:Buff 迷你世界 更新时间: 2023-04-26 20:07:54 具体函数名及描述如下: 序号 函数名 函数描述 1 addBuff(...) 给对象附加效果 2 removeBuff(...) 给对象移除指定效果 3 clearAllBuff(...) 给对象清除所有效果 4 clearAllBadBu…...
Java中Stream流的详细使用介绍
Java中Stream流的详细使用介绍 **1. 创建 Stream**从集合创建从数组创建使用 Stream.of 创建创建无限流 **2. 中间操作**过滤:filter映射:map去重:distinct排序:sorted截取:limit 和 skip **3. 终端操作**收集…...
【重构小程序】升级JDK1.8、SpringBoot2.x 到JDK17、Springboot 3.x(一)
前言 最近想着把大火的deepseek 迁移到小程序里,基于刷题小程序的数据库做一个RAG应用,来进一步扩展答案解析,帮助用户解答相关问题。但是由于之前做的项目都要老了,并不支持spring 的AI模块,因此,我打算先…...
功能丰富的自动化任务软件zTasker_2.1.0_绿色版_屏蔽强制更新闪退
🚀 zTasker 一键式效率倍增器使用指南 🙏 致谢 首先感谢开发者提供如此高效的工具! 软件本身功能强大,但部分机制需特别注意! 📖 软件概述 zTasker 是一款通过自动化脚本/任务流实现效率飞跃的生产力工…...
_ 为什么在python中可以当变量名
在 Python 中,_(下划线)是一个有效的变量名,这主要源于 Python 的命名规则和一些特殊的使用场景。以下是为什么 _ 可以作为变量名的原因和常见用途: --- ### 1. **Python 的命名规则** Python 允许使用字母ÿ…...
Java 9 到 Java 21 新特性全解析:从语法简化到API增强
一、新特性的概述 纵观Java这几年的版本变化,在Java被收入Oracle之后,Java以小步快跑的迭代方式,在功能更新上迈出了更加轻快的步伐。基于时间发布的版本,可以让Java研发团队及时获得开发人员的反馈,因此可以看到最近…...
LeeCode题库第三十九题
39.组合总和 项目场景: 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。 candidates 中的 同…...
卫星网络仿真平台:IPLOOK赋能空天地一体化通信新生态
卫星仿真平台 在6G技术加速演进与天地一体化网络建设的大背景下,卫星通信作为地面网络的重要补充,正成为全球通信覆盖的关键支撑。IPLOOK凭借其深厚的技术积累与创新实践,推出的卫星网络仿真平台(SCEPS),…...
(十一)基于vue3+mapbox-GL实现模拟高德实时导航轨迹播放
要在 Vue 3 项目中结合 Mapbox GL 实现类似高德地图的实时导航轨迹功能,您可以按照以下步骤进行: 安装依赖: 首先,安装 mapbox-gl 和 @turf/turf 这两个必要的库: npm install mapbox-gl @turf/turf引入 Mapbox GL: 在组件中引入 mapbox-gl 并初始化地图实例: <templ…...
计算机面试项目经历描述技巧
在计算机类岗位的面试中,项目经历是面试官评估候选人技术能力、问题解决能力和实战经验的核心环节。以下是专业化的项目经历描述策略(附模板框架): 一、结构化表达框架(STAR-RT模型) Situation(…...
132. 分割回文串 II
简单分析 输入的参数是字符串s,返回值是最小的切割次数。那这个问题的典型解法应该是动态规划,因为我们需要找最优解,而每一步的选择可能会影响后面的结果,但可以通过子问题的最优解来构建整体最优解。 那么动态规划的状态如何定…...
【每日学点HarmonyOS Next知识】全局调整字体、h5选择框无法取消选中、margin不生效、Length转换为具体值、Prop和link比较
【每日学点HarmnoyOS Next知识】全局调整字体、h5选择框无法取消选中、margin不生效、Length转换为具体值、Prop和link比较 1、HarmonyOS 是否存在统一调整全局字体大小的方法? 是否存在统一调整全局字体大小的方法 可以用动态属性,自定义class实现At…...
九、Spring Boot:自动配置原理
深入解析 Spring Boot 自动配置原理 Spring Boot 的自动配置机制是其最核心的特性之一,它极大地简化了 Spring 应用的初始搭建和开发过程。通过自动配置,Spring Boot 能够根据项目的依赖和配置自动加载和配置 Spring 应用的各个部分。本文将深入探讨 Sp…...
(动态规划 最长重复子数组)leetcode 718
思路就是建立一个二维的dp数组,只要nums1[i]nums2[j](nums1和nums2出现重复元素就置1 并加上左上角的值) 为什么代码是nums1 i-1和nums2 i-1 答:因为i和j以1为初始值开始遍历的 为什么要这么做并且为什么要加dp【i-1】【j-1】? …...
Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...
DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
拟合问题处理
在机器学习中,核心任务通常围绕模型训练和性能提升展开,但你提到的 “优化训练数据解决过拟合” 和 “提升泛化性能解决欠拟合” 需要结合更准确的概念进行梳理。以下是对机器学习核心任务的系统复习和修正: 一、机器学习的核心任务框架 机…...
数据挖掘是什么?数据挖掘技术有哪些?
目录 一、数据挖掘是什么 二、常见的数据挖掘技术 1. 关联规则挖掘 2. 分类算法 3. 聚类分析 4. 回归分析 三、数据挖掘的应用领域 1. 商业领域 2. 医疗领域 3. 金融领域 4. 其他领域 四、数据挖掘面临的挑战和未来趋势 1. 面临的挑战 2. 未来趋势 五、总结 数据…...
RabbitMQ work模型
Work 模型是 RabbitMQ 最基础的消息处理模式,核心思想是 多个消费者竞争消费同一个队列中的消息,适用于任务分发和负载均衡场景。同一个消息只会被一个消费者处理。 当一个消息队列绑定了多个消费者,每个消息消费的个数都是平摊的&a…...
Linux--vsFTP配置篇
一、vsFTP 简介 vsftpd(Very Secure FTP Daemon)是 Linux 下常用的 FTP 服务程序,具有安全性高、效率高和稳定性好等特点。支持匿名访问、本地用户登录、虚拟用户等多种认证方式,并可灵活控制权限。 二、安装与启动 1. 检查是否已…...
win11部署suna
参考链接 项目链接 沙盒链接 数据库链接 本文介绍 本文只为项目的辅助,手把手太麻烦 执行步骤 1.下载代码 git clone https://github.com/kortix-ai/suna.git cd suna2.配置环境(在Anaconda Prompt上执行) python setup.py3.运行代码 …...
