VS2005 调试模式和发布模式之间的巨大性能影响

Posted

技术标签:

【中文标题】VS2005 调试模式和发布模式之间的巨大性能影响【英文标题】:Huge performance impact between VS2005 debug mode and release mode 【发布时间】:2012-08-25 06:48:35 【问题描述】:

我遇到了一个问题,即 Win32 应用程序在调试和发布版本之间存在巨大的性能差异。发布需要 20 秒,而调试构建需要 6 分钟来初始化应用程序。这很痛苦,因为在调试时,在开始做任何事情之前进行初始化总是需要 6 分钟。所以我正在寻找一种方法来调整调试构建中的性能。

运行分析器后,我发现下面的代码是热点。

class CellList 
    std::vector<CellPtr>* _cells;
    iterator begin()  return (*_cells).begin(); 
    iterator end()    return (*_cells).end(); 
    reverse_iterator rbegin()  return (*_cells).rbegin(); 
    reverse_iterator rend()    return (*_cells).rend(); 
    ...


CellList _cellList = ...;

for (CellList::iterator itr = _cellList.begin(), end = _cellList.end(); itr < end; ++itr) 
  Cell* cell = *itr;
  if (cell->getFoo()) cell->setBar(true);
  else cell->setBar(false);


for (CellList::iterator itr = _cellList.rbegin(), end = _cellList.rend(); itr < end; ++itr) 
  Cell* cell = *itr;
  if (cell->getFoo2()) cell->setBar2(true);
  else cell->setBar2(false);

这些是时基分析结果中的热点。

std::operator< <std::_Vector_iterator<Cell *,std::allocator<Cell *> >,std::_Vector_iterator<Cell *,std::allocator<Cell *> > >
std::_Vector_const_iterator<Cell *,std::allocator<Cell *> >::operator<
std::reverse_iterator<std::_Vector_iterator<Cell *,std::allocator<Cell *> > >::operator*
std::reverse_iterator<std::_Vector_const_iterator<Cell *,std::allocator<Cell *> > >::reverse_iterator<std::_Vector_const_iterator<Cell *,std::allocator<Cell *> > ><std::_Vector_iterator<Cell *,std::allocator<Cell *> > >

我猜是迭代器操作没有被内联并导致这种巨大的差异。有什么办法可以改善这一点吗?只要还能在源代码中逐行逐行检查所有变量值,我就可以在发布模式下调试。

【问题讨论】:

您可以通过将_SECURE_SCL 和_HAS_ITERATOR_DEBUGGING 定义为0 来提高性能。 这里有一个关于 _SECURE_SCL 的链接:preshing.com/20110807/the-cost-of-_secure_scl 绝对值得一试!请发回你找到的东西! PS:你在这个列表中添加了多少需要 6++ 分钟的东西? 向量中超过 100k,有时超过 1M。 我无法在我的项目中添加 _SECURE_SCL=0 和 _HAS_ITERATOR_DEBUGGING=0。在提到的@paulsm4 文章中,两个预处理器都必须在所有源代码中定义,包括预构建库。我无法更改项目中包含的第 3 方库。或者有什么解决方法? 【参考方案1】:

差异是正常的。我会做的就是放置

#pragma optimize("",off)

#pragma optimize("",on)

围绕您要检查的方法,并将构建的其余部分保持在发布模式。

【讨论】:

如果我刚开始调试并且不知道错误在哪里,我是否只需将此#pragma 添加到一大堆源文件中?有什么建议吗? @Stan 猜猜……如果您知道错误在哪里,那可能会有所帮助。【参考方案2】:

6 分钟与 20 秒的比例为 18:1(为简单起见,将其称为 20:1)。

这意味着调试版本花费了 95% 的时间来做一些发布版本没有的额外事情。

好的,在调试器下运行。点击暂停按钮并查看调用堆栈。您将有 19/20 的机会看到花费了额外时间的原因。 多做几次就可以确定了。

当我这样做时,它正在执行类验证方法,这些方法在发布模式下被关闭。 通常它是通过不同的路径一遍又一遍地重新验证相同的数据。

在您的情况下,很可能是那些迭代器。 如果你没有做太多其他事情,他们很容易成为主导。

但不要猜测。

【讨论】:

【参考方案3】:

一个问题是,在 VC++ 调试版本中默认启用的“快速调试检查”会使您的代码速度降低多达五倍。他们偶尔会发现错误,但不足以证明您所看到的成本是合理的。有关详细信息,请参阅我的博文:

Visual C++ Debug Builds–”Fast Checks” Cause 5x Slowdowns

关闭它们,每个小功能都会明显加快。

【讨论】:

【参考方案4】:

如果您的减速仅在于调试器内部的初始化(但如果您将调试构建作为常规应用程序运行则不会),这是由 Visual Studio 为您正在使用的所有库加载调试符号引起的。这是意料之中的,但您可以微调从调试首选项中加载哪些符号。

一般来说,缺乏优化当然会减慢速度,但不是特别是在调试器内启动时。

【讨论】:

6 分钟的初始化执行时间是通过单独启动应用程序而不是在调试器中测量的。

以上是关于VS2005 调试模式和发布模式之间的巨大性能影响的主要内容,如果未能解决你的问题,请参考以下文章

如何在巨大的 json 文件之间执行最佳模式搜索?

vs2005不能调试ASP.NET程序

vs2010中release模式下调试程序

调试和发布之间有啥(性能)差异吗?

在发布模式下编译时不会发出 QNetworkAccessManager 完成信号(VS 2005)

要在 Visual C++ 2005 中启动调试模式,是不是必须提供调试版本链接库?