Я искал утечку памяти в DLL, построенной в Delphi 2007 для Win32. Память для переменных threadvar не освобождается, если потоки все еще существуют, когда DLL выгружается (нет активных вызовов DLL, когда она выгружается).
Вопрос: есть ли способ заставить Delphi освобождать память, связанную с переменными threadvar? Это не так просто, как просто не использовать их. Некоторые из существующих компонентов Delphi используют их, поэтому даже если DLL не объявляет их явно, она в конечном итоге их использует.
Немного подробностей. Я отследил это до вызова LocalAlloc, который происходит в ответ на использование переменной threadvar, которая является «оболочкой» Delphi для локального хранилища потока в Win32. Для любопытных: вызов выделения находится в исходном файле Delphi sysinit.pas. Соответствующий вызов LocalFree происходит только для потоков, которые получают DLL_THREAD_DETACH
вызовов. Если у вас есть несколько потоков в приложении и вы выгружаете DLL, не будет DLL_THREAD_DETACH
вызова для каждого потока. DLL получает DLL_PROCESS_DETACH
и больше ничего; Я считаю, что это ожидаемо и справедливо. Таким образом, происходит утечка любых выделений локальной памяти для других потоков.
Я воссоздал его с помощью короткой программы на C, которая запускает несколько «рабочих» потоков. Он загружает DLL (через LoadLibrary) в основной поток, а затем выполняет вызовы экспортируемой функции в рабочих потоках. Функция, экспортированная из Delphi DLL, присваивает значение целочисленной переменной threadvar и возвращает. Затем программа на C выгружает DLL (через FreeLibrary в основном потоке) и повторяет. Примерно после 32000 итераций использование памяти процессом, показанное в Process Explorer, вырастает до более 130 МБ. Я также более точно проверил это с помощью umdh. UMDH показал, что на каждый экземпляр потеряно 24 байта. Но 130 МБ в Process Explorer, по-видимому, указывают примерно на 4 КБ на итерацию; Я предполагаю, что каждый раз просочился сегмент 4K, но я не знаю наверняка.
Для пояснения вот объявление threadvar и вся экспортированная функция:
threadvar
threadint : integer;
function Startup( ulID: LongWord; hValue: Longint ): LongWord; stdcall;
begin
threadint := 123;
Result := 0;
end;
Спасибо.