Visual Studio调试运行极其缓慢

22

我有一个本地的C++程序,当使用 DebugF5)启动时,运行速度会变慢超过20倍;但当使用不带调试的启动方式(Ctrl+F5),则速度正常。

无论我使用debug还是release构建都没有影响。同时,如果我使用WinDbg,则该程序的运行速度会变得非常慢。

是否有某些设置选项我选择错误了,还是其他原因呢?


调试会给程序增加很多开销。你为什么要假设事情出了问题呢? - Oded
3
调试不应该增加太多的开销。连接调试器和未连接调试器之间的差异本不应存在。 - plaisthos
7个回答

18

我无法确认这是否真的是我的程序中的情况,但它确实听起来像是我的问题。 - plaisthos

14

当然,这并不是由于定义了_DEBUG符号或在调试配置中编译代码所导致的。添加的调试代码无论是否连接到程序都会运行。

调试器通常不影响代码执行,通过调用WaitForDebugEvent来保持远离程序。此操作将阻塞它,直到操作系统告诉它发生了值得注意的事情。这可能会触发调试器中的一系列代码,从而减慢程序速度。您可以在DEBUG_EVENT结构文档中查看事件列表。

稍微注释一下文档之外的内容:当以下事件发生时,调试器将介入并可能会减慢程序速度:

  • 程序加载或卸载DLL。在加载期间会发生很多事情,调试器会寻找一个调试符号文件(.pdb)。它可能会联系符号服务器以下载它。任何在DLL源代码中设置的断点都将被激活。这可能会相当缓慢,但效果是暂时的,并且通常只会减慢启动。您可以在“输出”窗口中看到加载/卸载通知。

  • 程序引发异常。这会在引发异常时立即激活调试器,即“第一次机会通知”。这可能非常有帮助,您可以使用“调试”+“异常”、“抛出”复选框,使调试器在引发异常时停止。您可以在“输出”窗口中看到通知消息。这会大大减慢引发并捕获异常的代码,并很可能是减慢程序速度的源头。不要使用异常进行流程控制。

  • 线程开始运行或终止。再次,在“输出”窗口中打印有通知消息。如果想通过此方式减速程序,则必须创建许多线程。

  • 当程序使用OutputDebugString()进行跟踪时。在“输出”窗口中可见。这是减缓速度的另一种好选择,如果没有连接到调试器,则输出将被忽略。您不应该有任何麻烦来诊断它作为导致问题的原因,明显的副作用是在“输出”窗口中看到大量的消息。

  • 当程序遇到断点时,通常不会引起困惑。但是有些断点会使程序变慢,却不会导致调试器中断。特别是条件断点、击中计数器、过滤器和击中操作会很慢。请使用“调试”+“窗口”+“断点”来查看定义的断点。


  • 在这里使用Prism,因此启动后加载了许多模块。看起来这是原因,是的。 - Ignacio Soler Garcia
    加载各种DLL符号往往是罪魁祸首。至少在我的情况下,它会随机使程序运行得像古老的286(甚至更慢)。即使是简单的printf()语句也需要很长时间才能完成。VS直到执行几分钟后才显示“正在加载…”对话框,这就使一切变得如此缓慢显而易见。 - huoneusto

    3
    当在调试器下创建进程时,默认情况下操作系统使用调试堆。调试堆对内存进行更多的验证,特别是在释放内存时。
    有几种可能的选项可以禁用调试堆:
    1. 在启动后立即附加到进程。这将允许您有意识地加快调试模式的性能,并完全了解您正在运行的模式。 2. 添加环境变量设置_NO_DEBUG_HEAP=1。这可以针对机器全局设置或特定的Visual Studio实例设置。 a. 全局设置环境变量:通过控制面板→系统→高级系统设置→环境变量,在那里添加变量_NO_DEBUG_HEAP=1。 注意:这将影响您调试的每个应用程序。 b. 对于Visual Studio实例,您可以打开命令提示符,设置环境变量_NO_DEBUG_HEAP=1,然后从该命令提示符内部打开Visual Studio。这将只影响从该Visual Studio实例创建的进程将继承环境变量。 3. 追加调试器的行为,这适用于VS2015。有两种方法可以覆盖此: a. 要修改特定项目,请转到项目属性配置属性→调试,并将环境属性_NO_DEBUG_HEAP更改为1。 b. 要修改Visual Studio中的每个项目,请转到工具→选项→调试并选中选项:“启用Windows调试堆分配器(仅限本机)”。 注意:如果在项目级别中设置了“a”中提到的_NO_DEBUG_HEAP环境变量,它将覆盖此全局设置。

    3
    对我而言,调试模式和发布模式之间的性能差异约为40倍。经过一些挖掘,发现有几个因素导致性能差异,但有一个编译器选项可以使我的调试性能几乎免费增加四倍。
    即将/ZI改为/Zi。有关说明,请参见MSDN页面
    我无论如何都不使用“编辑并继续”功能。

    1
    没有人提到关闭未使用的源窗口。
    关闭了20多个未使用的窗口后,调试源代码的步骤时间从大约5秒降至大约0.2秒。这个异常缓慢的项目动态加载了一个DLL,并且该DLL也是被跟踪和打开源窗口的一个,所以这似乎是相关的。但是这是C#(标题和标签不具体)。

    是的,IDE用户界面速度与运行应用程序完全不同。 - plaisthos
    我明白了,确实如此,希望能帮助到被引导到这里的人。 - crokusek

    1

    如果您在IDE之外运行调试版本,则有几个不同的事情。其中一个是IDE需要一段时间来加载符号,如果您依赖许多库,则启动时间可能会很长。

    如果您使用符号服务器(包括Microsoft公共符号服务器),则这可能会增加启动时间,因此请确保在_NT_SYMBOL_PATH变量中具有本地符号缓存。

    此外,IDE启用了调试堆,但我认为如果您在IDE之外运行,则不会发生这种情况。


    我正在使用符号服务器。但我说的不是启动时间,而是程序实际运行所需的时间。我使用std::cout进行诊断,Ctrl+F5每秒大约有一个输出,F5运行时每30秒左右输出一次。我认为堆调试取决于_DEBUG宏,它将在两种情况下进行堆检查。 - plaisthos
    你有设置任何条件断点或跟踪点吗?这些可能会使执行速度减慢十倍。尝试暂时禁用所有断点。 - the_mandrill
    很遗憾,我没有这样的东西。那将会太容易了 :) - plaisthos
    关于任何插件怎么样?另外一个尝试的方法是运行进程监视器,看看devenv.exe进程是否正在访问任何文件。我发现有些情况下这种情况经常发生——devenv一直在访问我的头文件。还可以尝试删除.suo文件。 - the_mandrill

    0

    调试 Visual C++ 带来了很多开销,特别是在 STL 中。尝试不定义 _DEBUG,并定义 NDEBUG


    3
    不过,这并没有回答提问者的问题——它仍然是一个调试版本,只是在IDE之外运行。STL诊断仍将运行。 - the_mandrill

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接