Delphi:使用调试器调用 C dll 函数需要 15 秒,没有调试器需要 0.16 秒。为什么?

Delphi: Calling a C dll function with Debugger takes 15 s without debugger 0.16 s. Why?

我有以下设置:

  1. 用 Delphi XE5 编写并内置 Debug 64 位的 Delphi 命令行应用程序。
  2. 用 Microsoft Visual Studio 2013 编写并内置于 64 位版本的 C dll。
  3. Delphi 命令行应用程序调用 C dll 中的函数。

意外情况:

  1. 在 Delphi XE5 IDE 中调试 Delphi 命令行应用程序时,C dll 函数调用需要 15 秒。
  2. 当直接启动相同的 Delphi 命令行应用程序时(没有 IDE,没有调试器),C dll 函数调用需要 0.16 秒。

Delphi命令行应用程序源代码:

program DelphiCpplibraryCall;
{$APPTYPE CONSOLE}
{$R *.res}
uses
  System.SysUtils,
  Windows;

type
  TWork = function(Count : Integer) : Integer; cdecl;
var
  Handle : THandle;
  Work   : TWork;
  Result : Integer;
  Freq   : Int64;
  Start  : Int64;
  Stop   : Int64;
begin
  try
    Handle := LoadLibraryEx('worker.dll', 0, LOAD_WITH_ALTERED_SEARCH_PATH);
    Work := GetProcAddress(Handle, 'work');

    QueryPerformanceFrequency(Freq);
    QueryPerformanceCounter(Start);
    Result := Work(500000);
    QueryPerformanceCounter(Stop);
    Writeln(Format('Result: %d Time: %.6f s', [Result, (Stop-Start) / Freq]));

    FreeLibrary(Handle);

    Readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

C dll源代码:

#include "worker.h"
#include <unordered_map>

class Item
{
public:
    Item(const int value = 0) : _value(value) {}
    virtual ~Item(void) {}
private:
    int _value;
};

int work(int count)
{
    typedef std::unordered_map<int, Item> Values;
    Values* values = new Values;
    int k = 0;
    for (size_t i = 0; i < count; i++)
    {
        (*values)[i] = Item(i);
        k++;
    }
    delete values;
    return k;
}

Delphi + C dll源代码:DelphiCpplibraryCall.zip

运行时比较:

出于某种原因,Delphi 调试器似乎大大减慢了 C dll 函数调用的速度,这使得调试几乎不可能。

有没有人知道什么可能导致这个问题或如何避免它?非常感谢。

编辑: 我现在可以确认所描述的行为根本不限于 Delphi IDE 和调试器。如果我:

,也会发生此问题
  1. 我在 Microsoft Visual Studio 2013 Release 中构建 C dll。
  2. 并在 Visual Studio 2013 年构建和调试调用 C dll 的命令行可执行文件。

这意味着 C dll 发布构建函数的执行时间会根据是否附加调试器而变化。

我还可以确认,只要存在调试器,删除 unordered_map (delete values;) 就需要这么长时间。

这似乎是此 STL 容器的 MSVC 实现的问题。使用 Visual Studio 调试器时可以看到完全相同的行为。 MSVC 运行时在检测到调试器时正在切换行为。

我找到了与此问题相关的以下链接:

很大一部分问题似乎是清除地图时的性能问题。只需从您的 C++ 代码中删除 delete 行即可看到显着提高的性能。

我找不到解决此问题的可行方法。

如果延迟来自 delete 调用,则可能是使用 Windows 堆内存管理器的内存管理器 (malloc)。当释放内存并附加调试器时,堆内存管理器会执行额外的广泛检查。

可以通过将环境变量 _NO_DEBUG_HEAP 设置为 1(以下划线开头)来禁用这些附加检查。

您可以在 Delphi 中针对 Project/Options.../Debugger/Environment Block 下的特定项目执行此操作,或者您可以将 _NO_DEBUG_HEAP 添加到 Control Panel/System Properties/Advanced System Settings/Environment Variables/System Variables 下的用户环境块中,以便它适用于所有人项目和所有应用程序。但随后您可能需要注销以应用更改或至少重新启动 IDE.