本书关注对体现C++设计最佳实践的正确代码进行优化。开发人员往往缺乏现代微处理器设备的基本常识,或是没有仔细考虑各种C++对象构建方式的性能开销而编写出的运行缓慢的代码。
性能优化的目的是通过改善正确程序的行为使其满足客户对处理速度、吞吐量、内存占用以及能耗等各种指标的需求。
bug修复与性能优化之间的一个重要区别是,性能是一个连续变量。bug要么存在,要么不存在。但是性能可以是非常糟糕或者非常优秀,还可以介于这二者之间。优化还是一个迭代过程。每当程序中最慢的部分被改善后,一个新的最慢的部分就会出现。
与其他编码任务相比,优化更像是一门实验科学,需要有更深入的科学思维方式。要想优化成功,需要先观察程序行为,然后基于这些程序行为作出可测试的推测,在进行实验得出测试结果。实验,而非直觉,才是贯穿本书的主题。
不过,通过微调代码让程序的运行速度提升10多倍几乎是不可能的。但是选择一种更好的算法或是数据结构,则可以将程序的某个特性的性能从慢到无法忍受提升至可接受的状态。
“百分之九十七的情况下,过早优化都是万恶之源。”
“以效率之名犯下的计算之罪比其他任何一个原因都多。”
过度推崇这条建议经常被用作两种行为的接口:编程恶习,以及逃避做少量分析以让代码运行的更快。
处理器的处理速度越快,被浪费的指令的累积速度也会越快。
围堵惯犯,和恶魔隐藏在细节之中。
C++有一些热点代码是性能的“惯犯”:函数调用、循环和内存分配。
多数情况下,只要打开了优化选项,你都不用做额外的优化,因为编译器就可以让程序的运行速度提高数倍。
不过,优化选项可能会将代码移除循环、移除一些函数调用和完全移除一些变量。
选择一个最优算法对性能优化的效果最大。各种优化手段都能改善程序的性能。
Boost Project和Google Code等公开了很多可供使用的库。
要想隐藏高度优化后的程序的复杂性,函数和类库是非常合适的地方。库函数通常位于深层嵌套调用链的底端,在哪里,性能改善的效果会更加明显。
减少对内存管理器的调用是一种非常有效的优化手段。绝大多数C++语言特性的性能开销最多只是几个指令,但是每次调用内存管理器的开销却是几千个指令。
对缓存复制函数的一次调用也可能消耗数千个CPU周期。大量复制的发生都与内存分配有关,其他可能发生复制的热点代码是构造函数和赋值运算符以及输入输出。
除了内存调用外,单条C++语句的性能开销通常都很小。但是如果在循环执行许多次这条语句,这些开销就不小了。找出并优化这些循环几乎总是可以让性能优化硕果累累。
除非一段代码真的是热点语句,否则从中移除一两句内存访问对程序的整体性能不会有什么改善。
选择最合适的数据结构对性能有着深刻的影响,因为插入,迭代,排序和检索元素的算法的运行时的开销取决于数据结构。除此之外,不同的数据结构在使用内存管理器的方式上有所不同。另一个原因是数据结构孔内也可能没有优秀的缓存本地化。
现代计算机都可以使用多个处理器核心来执行指令。如果一项工作被分给几个处理器执行,那么它可以更快地执行完毕。伴随并发执行而来的是用于同步并发线程让它们可以共享数据的工具。
内存管理器作为C++运行时库总一部分,管理这动态内存分配。