C++ 应用程序性能优化

C++ 应用程序性能优化

eryar@163.com

1. Introduction

对于几何造型内核OpenCASCADE,由于会涉及到大量的数值算法,如矩阵相关计算,微积分,Newton迭代法解方程,以及非线性优化的一些算法,如BFGS,FRPR,PSO等等用于多元函数的极值求解,所以这些数值算法的性能直接影响系统的性能。软件的性能优化是计算机软件开发过程中需要一直关注的重要因素,因此有必要学习下C++应用程序性能优化的方法。

在网上寻找相关资料时,发现这方面的资料也很少,最后发现一本由电子工业出版社出版的《C++应用程序性能优化方法》,从中可以学习下IBM的性能优化方法。

本文主要结合《C++性能优化方法》并结合代码实例来说明内存优化处理对程序性能的影响。看完本书,其实发现C++性能优化方法主要还是依赖的计算机相关的基础知识,比如说计算机操作系统,数据结构与算法等等。

2.Memory Optimize

C++程序中的存储空间可以分为静态/全局存储区,栈区和堆区。静态/全局存储区和栈区的大小一般在程序编译阶段决定;而堆区则随着程序的运行而动态变化,每一次程序运行都会有不同的行为。这种动态的内存管理对于一个程序在运行过程中占用的内存大小及程序的性能有非常重要的影响。

因为静态/全局存储区在编译时就已经确定了,而栈区则是由操作系统在管理,这些都不劳程序员费神。就是这个堆区是提供给程序员的自由舞台,可以任性发挥。堆区的存储区域怎么玩呢?理解了这三个问题应该就知道了:一是堆区数据怎么产生(从哪儿来)?二是堆区的数据怎么销毁(到哪儿去)?堆区数据怎么访问?由C++标准规定得知,C++实现通过全局的new和delete来提供动态内存的访问和管理。而堆区数据的访问就是通过指针了。当使用new/delete来操作堆上的存储区域时,操作系统就要对堆的存储区域进行管理,所以这个管理工作就会对应用程序的性能有影响。

为了解决内存泄露问题,即new之后不再使用时并没有delete,OpenCASCADE中入了Handle智能指针的宏定义。Handle的使用也很简单,只需要将用Handle(Class)就可以了。

利用默认的内存管理new/delete在堆上分配和释放内存会有一些额外的开销。系统在接收到一定大小内存请求时,首先查找内部维护的内存空闲块表,并且需要根据一定的算法(例如分配最先找到的不小于申请大小的内存块给请求者,或者分配最适于申请大小的内存块等)找到合适大小的内存块。如果该空闲内存块过大,还需要切割成已分配的部分和较小的空闲块,然后系统更新内存块表,完成一次内存分配。类似地,在释放内存时,系统把释放的内存块重新加入到空闲内存块表中。如果有可能的话,可以把相邻的空闲块合并成较大的空闲块。

默认的内存管理函数还考虑到多线程的应用,需要在每次分配和释放内存时加锁,同样增加开销。可见,如果应用程序频繁地在堆上分配格释放内存,则会导致性能的损失。并且会使系统中出现大量的内存碎片,降低内存的利用率。

由此可见,在简单的new和delete背后,系统默默地为我们做了这么多的事,而做这些事都是要花时间的啊!虽然默认的内存管理算法也考虑了性能,但是考虑的是更通用的情况,为了应付更复杂、更广泛的情况,需要做更多额外工作。而对于具体的应用程序来说,适合自身特定的内存管理则可以获得更好的性能,为此OpenCASCADE引入了自己的内存管理机制,与内存池概念类似。OCCT的内存通过配置,可以使用没的优化技术,或者不使用任何优化直接使用系统的malloc和free。这些配置都是通过环境变量来实现,其中打开和关闭内存优化的开关是环境变量:MMGT_OPT,这个默认是0,即不使用任何优化;设置成1就是使用;设置成2就是使用TBB的内存优化技术(这个的前提是第三方库正确配置,如果没有还是使用的malloc和free;

// paralleling with Intel TBB
#ifdef HAVE_TBB
  #include <tbb/scalable_allocator.h>
  using namespace tbb;
#else
  #define scalable_malloc malloc
  #define scalable_calloc calloc
  #define scalable_realloc realloc
  #define scalable_free free
#endif

下面通过代码来看看使用内存管理的性能有什么变化。

3.Code Example

下面通过程序来看看使用这些技术对性能的影响:

/*
*    Copyright (c) 2016 Shing Liu All Rights Reserved.
*
*           File : main.cpp
*         Author : Shing Liu(eryar@163.com)
*           Date : 2016-07-31  11:54
*        Version : OpenCASCADE7.0.0
*
*    Description : Test OCCT Memory Manager and Handle(smart pointer).
*/

#include <OSD_Timer.hxx>

#include <Poly.hxx>
#include <Poly_Triangulation.hxx>

#pragma comment(lib, "TKernel.lib")
#pragma comment(lib, "TKMath.lib")

/*
*@brief test memory without Handle(smart pointer) management.
*
 */
void testMemory(Standard_Integer theCount)
{
    OSD_Timer aTimer;
    aTimer.Start();

    for (Standard_Integer i = 0; i < theCount; i++)
    {
        Poly_Triangulation* aTriangulation = new Poly_Triangulation(10, 5, Standard_False);

        delete aTriangulation;
    }

    aTimer.Stop();
    aTimer.Show();
}

/*
*@brief test memory with Handle(smart pointer) management.
*
*/
void testHandle(Standard_Integer theCount)
{
    OSD_Timer aTimer;
    aTimer.Start();

    for (Standard_Integer i = 0; i < theCount; i++)
    {
        Handle(Poly_Triangulation) aTriangulation = new Poly_Triangulation(10, 5, Standard_False);
    }

    aTimer.Stop();
    aTimer.Show();
}

/*
* @brief set environment variable MMGT_OPT=0 to use malloc/free directly;
*        set environment varialbe MMGT_OPT=1 to use OCCT memory optimization technique;
*        set environment variable MMGT_OPT=2 to use paralleling with Interl TBB;
 */
int main(int argc, char* argv[])
{
    int aCount = 100000;

    std::cout << "\ntest pointer without handle" << std::endl;
    testMemory(aCount);

    std::cout << "\ntest pointer with handle" << std::endl;
    testHandle(aCount);

    return 0;
}

如果直接运行上面的代码编译的程序,得到的结果如下图所示:

由图可知,当使用Handle(智能指针)的时候,时间上影响不大,即使用Handle对性能影响基本上可以忽略,但是得到很多好处,主要的就是不用自己去delete了。使用Visual Studio的性能分析工具查看,结果也类似:

时间的开销也是集中在内存的分配上面:

注意到上面的Allocate()是类Standard_MMgrRaw的,即是直接使用的系统的malloc和free来管理内存。下面设置环境变量MMGT_OPT=1来使用OCCT的内存优化类看看对性能影响如何?

程序运行的结果如下图所示:

与没有使用内存优化的时候0.1相比,使用了内存优化处理的要快40%左右。

由下图可以看出,性能热点也是集中在内存的分配上面:

注意现在内存分配使用的是Standard_MMgrOpt类中的Allocate函数:

总的来说,将环境变量MMGT_OPT设置成1来使用OCCT的内存优化算法,性能提升还是很明显的。

4.Conclusion

当程序规模越来越大,算法越来算复杂的时候,找到性能的瓶颈越麻烦一些。性能优化第一步是测量,找到合适的测量工具。《C++应用程序性能优化》一书中提供的是IBM Rational Quantify,在网上搜了下还有Intel VTune Amplifier等,功能都很强大。在Windows中开发程序使用的Visual Studio自带了性能分析功能,使用起来也比较方便。

找到性能瓶颈,就要对其进行分析原因,进而修改程序,提高性能。这方面的方法论可以借鉴《C++应用程序性能优化》,从数据结构、程序启动、内存管理等方面来分析。摘出此书中程序性能优化的流程图:

5. References

1.冯宏华,徐莹,程远,汪磊. C++应用程序性能优化. 电子工业出版社.

2.Scott Meryers. Effective C++(评注版). 电子工业出版社. 2011

3.OpenCASCADE Foundation Classes Document 7.0.0. 2016

PDF Version: C++应用程序性能优化

时间: 2024-10-22 08:42:44

C++ 应用程序性能优化的相关文章

Hibernate程序性能优化的考虑要点

程序|性能|优化 本文依照HIBERNATE帮助文档,一些网络书籍及项目经验整理而成,只提供要点和思路,具体做法可以留言探讨,或是找一些更详细更有针对性的资料. 初用HIBERNATE的人也许都遇到过性能问题,实现同一功能,用HIBERNATE与用JDBC性能相差十几倍很正常,如果不及早调整,很可能影响整个项目的进度. 大体上,对于HIBERNATE性能调优的主要考虑点如下: Ø 数据库设计调整 Ø HQL优化 Ø API的正确使用(如根据不同的业务类型选用不同的集合及查询API) Ø 主配置参

Java程序性能优化(辛苦了几个小时,还经历了一次停电,我真是命苦!)

程序|性能|优化 Java程序性能优化 一.避免在循环条件中使用复杂表达式 在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快. 例子:import java.util.Vector;class CEL {    void method (Vector vector) {        for (int i = 0; i < vector.size (); i++)  // Violation            ; //

ASP.NET程序性能优化五则

asp.net|程序|性能|优化 一.使用存储过程: 1.性能方面:存储过程提供了许多标准sql语言中所没有的高级特性.其传递参数和执行逻辑表达式的功能,有助于应用程序设计者处理复杂任务.另外,存储过程存储在本地服务器上,减少了执行该过程所需的网络传输宽带和执行时间.(存储过程已经对sql语句进行了预编译,所以其执行速度比在程序里执行sql语句快很多) 2.程序结构方面:从程序的可扩展性看,使用存储过程会对程序以后的修改带来方便.比如数据库的结构改变了,只需修改相对应的存储结构,和程序中的调用部

ASP.NET应用程序性能优化

asp.net|程序|性能|优化 [把前一段时间给单位项目所做性能优化的一些想法整理了以下,分享交流] ASP.NET 应用程序性能优化 1 前言性能优化的主要目标是提高"并发用户数量","吞吐量","可靠性"这样几个指标. 本质上说,性能优化的工作应该是多方面的,要做到"点面结合.由表及里".比如:从代价的角度来考虑,应尽量做到改动量小,易实施:从用户角度看,应做到快速响应或快速提示:从软件结构的角度看,又要兼顾到系统结构的

Java 程序性能优化《第一章》Java性能调优概述 1.4小结

Java 程序性能优化<第一章>1.4小结 通过本章的学习,读者应该了解性能的基本概念及其常用的参考指标.此外,本章还较为详细的介绍了与性能调优相关的两个重要理论--木桶原理以及Amdahl定律. 根据木桶原理,系统的最终性能总是由系统中性能最差的组件决定的.因此,改善该组件的性能对提升系统整体性能有重要的作用.而根据Amdahl定律,可以知道只是增加处理器数量对提升系统性能并没有太大的实际意义,必须同时提高程序的并行化比重. 本章还简要的介绍了在软件开发和维护过程中可以进行性能优化的各个阶段

java 程序性能优化《第二章》设计优化 2.1善用设计模式 1 单例模式

java 程序性能优化<第二章>设计优化 2.1善用设计模式 1 单例模式 设计模式是前人工作的总结和提炼.通常,被人们广泛流传的设计模式都是对某一特定问题的成熟的解决方案.如果能合理的使用设计模式,不仅能使系统更容易被他人理解,同时也能使系统拥有更加合理的结构.本节总结归纳了一些经典的设计模式,并详细说明它们与软件性能之间的关系. 2.1.1 单例模式 单例模式是设计模式中使用最为普遍的模式之一.它是一种对象创建模式,用于生产一个对象的具体实现,它可以确保系统中一个类只产生一个实例.在Jav

Java 程序性能优化《第一章》Java性能调优概述 1.2性能调优的层次

Java 程序性能优化<第一章>1.2性能调优的层次 为了提升系统性能,开发人员开始从系统各个角度和层次对系统进行优化.除了最常见的代码优化外,在软件架构上.JVM虚拟机层.数据库以及操作系统层面都可以通过各种手段进行优化,从而在整体上提升系统的性能. 1.2.1 设计调优 设计调优处于所有调优手段的上层,它往往需要在软件开发之前进行.在软件开发之处,软件架构师就应该评估系统可能存在的各种潜在问题,并给出合理的设计方案.由于软件设计和架构对整体质量有决定性的影响,所以,设计调优对系统性能的影响

Java 程序性能优化《第一章》Java性能调优概述 1.3基本调优策略和手段

Java 程序性能优化<第一章>1.3基本调优策略和手段 存在性能问题的系统,十之八九是由于某一系统瓶颈导致的.只要找到该性能瓶颈,分析瓶颈的形成原因,对症下药,使用合理的方法解决系统瓶颈,就能从根本上提升性能.所以,系统性能优化的最主要目的就是查找并解决性能瓶颈问题.但同时值得注意的是,性能优化往往会涉及对原有的实现进行较大的修改,因此,很难保证这些修改不引入新的问题.所以,在性能优化前,需要对性能优化的目标.方法进行统筹的安排. 1.3.1 优化的一般步骤 对软件系统进行优化,首先需要有明

也谈ASP.NET应用程序性能优化

[把前一段时间给单位项目所做性能优化的一些想法整理了以下,分享交流]ASP.NET 应用程序性能优化1 前言性能优化的主要目标是提高"并发用户数量","吞吐量","可靠性"这样几个指标.本质上说,性能优化的工作应该是多方面的,要做到"点面结合.由表及里".比如:从代价的角度来考虑,应尽量做到改动量小,易实施:从用户角度看,应做到快速响应或快速提示:从软件结构的角度看,又要兼顾到系统结构的合理性和可扩展性.由此不难发现,在尝试一

java 程序性能优化《第二章》设计优化 2.1善用设计模式 2 代理模式

java 程序性能优化<第二章>设计优化 2.1善用设计模式 2 代理模式 代理模式也是一种很常见的设计模式.它使用代理对象完成用户请求,屏蔽用户对真实对象的访问.就如同现实中的代理一样,代理人被授权执行当事人的一些适宜,而无需当事人出面,从第三方的角度看,似乎当事人并不存在,因为他只和代理人通信.而事实上,代理人是要有当事人的授权,并且在核心问题上还需要请示当事人. 在现实中,使用代理的情况很普遍,而且原因也很多.比如,当事人因为某些隐私不方便出面,或者当事人不具备某些相关的专业技能,而需要