У меня есть следующие настройки:
Что неожиданно:
Исходный код приложения командной строки 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 soure код: DelphiCpplibraryCall.zip
Сравнение времени выполнения:
По какой-то причине Delphi Debugger, похоже, сильно замедляет вызов функции Cll, что делает почти невозможной отладку.
Кто-нибудь знает, что может быть причиной этой проблемы или как ее избежать? Большое спасибо.
Редактировать: Теперь я могу подтвердить, что описанное поведение не ограничивается только Delphi IDE и Debugger. Эта проблема также происходит, если я:
Это означает, что время выполнения функции сборки релиза C dll изменяется в зависимости от того, подключен ли отладчик или нет.
Я также могу подтвердить, что это удаление unordered_map (delete values;
) это занимает столько времени, как только присутствует отладчик.
Если задержка исходит от delete
тогда вызов может быть диспетчером памяти (malloc), который использует диспетчер памяти кучи Windows. Менеджер памяти кучи выполняет дополнительные расширенные проверки, когда освобождается память и подключается отладчик.
Эти дополнительные проверки можно отключить, установив переменную среды _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.
Похоже, что это проблема с реализацией MSVC этого контейнера STL. Точно такое же поведение можно увидеть при использовании отладчика Visual Studio. Среда выполнения MSVC переключает поведение при обнаружении отладчика.
Я нашел следующие ссылки, связанные с этой проблемой:
Большая часть проблемы, по-видимому, связана с производительностью при очистке карты. Просто удалите delete
линия из вашего кода C ++, чтобы увидеть значительно улучшенную производительность.
Я не могу найти способ обойти эту проблему.