Я преследовал то, что кажется утечкой памяти в 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) в основной поток и затем выполняет вызовы в экспортированную функцию на рабочих потоках. Функция, экспортированная из DLL Delphi, присваивает значение целочисленной переменной threadvar и возвращается. Затем программа C выгружает DLL (через FreeLibrary в основной поток) и повторяет. После примерно 32 000 итераций использование памяти процесса, отображаемое в Process Explorer, превышает 130 МБ. Я также более точно проверил его с помощью umdh. UMDH показал 24 байта, потерянных для каждого экземпляра. Но 130MB в Process Explorer, по-видимому, указывает около 4K на итерацию; Я предполагаю, что 4K-сегмент был утечка каждый раз на основе этого, но я не знаю точно.
Для пояснения, вот объявление threadvar и вся экспортированная функция:
threadvar
threadint : integer;
function Startup( ulID: LongWord; hValue: Longint ): LongWord; stdcall;
begin
threadint := 123;
Result := 0;
end;
Спасибо.