8

我有以下设置:

  1. 用 Delphi XE5 编写并内置 Debug 64 位的 Delphi 命令行应用程序。
  2. AC dll 用 Microsoft Visual Studio 2013 编写并内置于 64 位版本。
  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

运行时比较:

  • 第一个控制台:在 IDE 中调试时
  • 第二个控制台:在没有 IDE 的情况下启动

运行时比较

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

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

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

  1. 我在 Microsoft Visual Studio 2013 的 Release 中构建了 C dll。
  2. 并在 Visual Studio 2013 中构建和调试调用 C dll 的命令行可执行文件。

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

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

4

2 回答 2

6

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

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

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

Delphi 项目选项环境块

于 2015-08-27T22:00:56.390 回答
3

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

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

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

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

于 2015-08-27T14:17:25.230 回答