C++性能优化
C++ 性能优化的核心原则可以总结为:减少不必要的计算、提升内存访问效率、发挥硬件并行能力,以及利用编译期优化。
- 内存与缓存优化(现代 CPU 性能的关键)
提升数据局部性(Data Locality): 优先使用连续内存存储的容器(如 std::vector、std::array),减少对节点型容器(如 std::list、std::map)的使用,避免 CPU Cache Miss。
自定义内存分配器: 对于频繁创建/销毁的小对象,标准库的 malloc 或 new 会带来较大的开销与内存碎片。使用内存池(Memory Pool)或对象池能大幅提升分配效率。
优化结构体对齐(Memory Alignment): 调整结构体成员的排列顺序,按字节大小降序排列,减少补齐(Padding)字节;在多线程场景下要注意防止伪共享(False Sharing),通过 alignas(64) 将频繁修改的变量隔离在不同的缓存行(Cache Line)中。
- 语法与语言特性层面 减少不必要的拷贝(零拷贝与移动语义):
使用移动语义(Move Semantics):合理实现/利用移动构造和移动赋值,避免深拷贝。
值传递与引用传递: 复杂对象优先选择 const T& 传递;只读字符串使用 std::string_view(C++17),数组切片使用 std::span(C++20)。
原地构造: 使用 emplace_back 替换 push_back,避免临时对象的创建与拷贝。
利用编译期计算:
尽可能使用 constexpr / consteval 将计算从运行期提前到编译期完成。
减少虚函数与非必要动态绑定:
虚函数调用存在指针寻址开销,且阻碍编译器进行内联优化。对不需要被继承的类或虚函数标记 final,方便编译器进行去虚化(Devirtualization)。
采用 CRTP(Curiously Recurring Template Pattern,奇异递归模板模式) 实现静态多态。
- 算法与数据结构选择 选对数据结构: 查找密集型场景下,无序哈希表 std::unordered_map 通常比基于红黑树的 std::map 更高效;但数据量较小时,甚至连续数组 std::vector 加线性查找的速度都可能超过哈希表(因为 Cache 更友好)。
预分配内存容量: 对于 std::vector、std::string 等可扩容容器,在已知元素数量或大致范围时,提前调用 .reserve() 避免多次重新分配内存和搬运数据。
- 编译器优化选项与 PGO 许多性能提升只需开启编译器的优化开关:
基础优化等级: 发布版本务必开启 -O2 或 -O3(Clang/GCC)或 /O2(MSVC)。
PGO(Profile-Guided Optimization,基于性能分析的优化):
带 Instrumentation 标志编译程序,跑一遍典型业务流程收集 Profile 数据。
编译器利用这些数据重新编译(优化热点代码分支预测、函数内联与代码布局),通常能带来 5%~20% 的额外提升。
LTO / LTCG(Link-Time Optimization,链接期优化): 开启 -flto,打破跨编译单元(.cpp 文件)的壁垒,实现跨文件的函数内联和无用代码消除。
针对架构指令集优化: 指定 -march=native,允许编译器使用当前 CPU 支持的高级指令集(如 AVX2、AVX-512)。
- 多线程与并发优化 无锁(Lock-Free)编程: 在高并发读写热点上,尝试用 std::atomic 替换互斥锁 std::mutex;注意选择合适的内存顺序(Memory Order,如 std::memory_order_relaxed),避免过强同步锁死流水线。
线程池化: 避免频繁创建和销毁线程,采用任务队列 + 线程池模式复用工作线程。
cyclone 性能下降问题怎么比较优化结果 https://confluence.ext.net.nokia.com/pages/viewpage.action?pageId=1857328842
https://confluence.ext.net.nokia.com/pages/viewpage.action?spaceKey=5GRD&title=Cyclone
PGO 优化
Cyclone provides a method to monitor performance KPIs during test execution. KPIs like #instructions, #cycles consumed per slot and per scheduler phase (TD - FD - PostTd) can help identify bottlenecks or performance degradation in continuous integration.
Additionally more KPIs are tracked for snowfish (ABIO) that leverage Intel’s capability of TOPDOWN performance analysis. e.g; FE_ICACHE or FE_PREDECODE. TOPDOWN approach details here: Intel+Top-Down+Analysis+for+Processor+Performance
Monitoring is achieved by pushing these measured KPIs to a Grafana dashboard. Variations in L2-PS performance can be then easily tracked and fixed.
U-Plane SW Performance Aspects
3.1. TSC - Time Stamp Counter Counts the number of CPU cycles.
3.2. INS - Instructions Retired Event How many instructions were completely executed.
算法复杂度,单独开一期来写
任务切换 同一进程,共享地址空间,页表,代码段,只需要切寄存器和栈。 不同进程,除了寄存器,还要换页表,虚拟地址空间,TLB 进程切换 > 线程切换 > 函数调用 切换为导致 Cache失效, 性能下降
让同一个线程长期跑在同一个核上。Cache一直热着,性能会好很多。 通信软件常做的就是 线程绑定CPU核。
上下文切换本质上就是“给当前线程拍快照保存,再把另一个线程的快照恢复回来”。真正昂贵的不只是保存寄存器,而是切换后原来缓存中的代码和数据失效,导致CPU需要重新把新线程的工作集装入Cache,这部分成本往往远高于寄存器保存本身。
扩展阅读
[1] Optimized C++ by Kurt Guntheroth(O’Reilly). Copyright 2016 Kurt Guntheroth, 978-1-491-92206-4