Исправление Утечки Памяти в DLL для Delphi 2007: Освобождение Памяти для threadvar
Вопрос утечки памяти в DLL, созданных с использованием Delphi, является актуальной проблемой для разработчиков. Особенно это касается использования переменных threadvar, которые предназначены для хранения данных в каждом потоке отдельно, но при этом могут приводить к утечкам памяти, если не обработать их корректно.
Понимание Проблемы
Пользователь столкнулся с утечкой памяти в DLL, созданной в Delphi 2007 для Win32. Проблема заключается в том, что память для переменных threadvar не освобождается, если потоки все еще существуют при выгрузке DLL. Это связано с тем, что вызов функции LocalFree происходит только для потоков, которые получают уведомление DLL_THREAD_DETACH, но при выгрузке DLL такого уведомления не поступает.
Решение Проблемы
Для решения проблемы можно использовать следующий подход:
Хранение указателей на выделенную память для каждого потока в глобальном списке.
Освобождение памяти из списка при выгрузке DLL (в функции DllMain с параметром DLL_PROCESS_DETACH).
Пример кода на Object Pascal (Delphi):
library Sample;
uses
SysUtils,
Windows,
Classes,
SyncObjs;
{$E dll}
var
gListSync : TCriticalSection;
gTLSList : TList;
threadvar
threadint : integer;
procedure RemoveAndFreeTLS();
var
i : integer;
begin
// Освобождение всех выделенных блоков памяти
if assigned(gTLSList) then
for i := 0 to gTLSList.Count - 1 do
LocalFree(Cardinal(gTLSList.Items[i]));
end;
procedure RemoveThreadTLSEntry();
var
p : pointer;
begin
// Удаление указателя текущего потока из списка
gListSync.enter;
try
if (SysInit.TlsIndex <> -1) and assigned(gTLSList) then
begin
p := TlsGetValue(SysInit.TlsIndex);
if p <> nil then
gTLSList.Remove(p);
end;
finally
gListSync.leave;
end;
end;
procedure AddThreadTLSEntry();
var
p : pointer;
begin
gListSync.enter;
try
// Создание списка, если это первый вызов
if not assigned(gTLSList) then
gTLSList := TList.Create;
if SysInit.TlsIndex <> -1 then
begin
p := TlsGetValue(SysInit.TlsIndex);
if p <> nil then
begin
// Добавление указателя в список, если его там еще нет
if gTLSList.IndexOf(p) = -1 then
gTLSList.Add(p);
end;
end;
finally
gListSync.leave;
end;
end;
function MyExportedFunc(): LongWord; stdcall;
begin
threadint := 123;
// Добавление указателя текущего потока в глобальный список
AddThreadTLSEntry;
Result := 0;
end;
procedure DllMain(reason: integer);
begin
case reason of
DLL_PROCESS_DETACH:
begin
// Освобождение памяти при выгрузке DLL
RemoveAndFreeTLS();
gListSync.Free;
if assigned(gTLSList) then
gTLSList.Free;
end;
DLL_THREAD_DETACH:
begin
// Удаление указателя из списка при завершении потока
RemoveThreadTLSEntry();
end;
end;
end;
exports
DllMain,
MyExportedFunc;
initialization
begin
IsMultiThread := TRUE;
DllProc := @DllMain;
gListSync := TCriticalSection.Create;
end.
Важные Моменты
При использовании threadvar с динамическими типами данных, такими как строки, массивы или интерфейсы, разработчик обязан самостоятельно освободить выделенную память перед завершением потока.
В коде необходимо использовать механизмы синхронизации, чтобы избежать гонки данных при доступе к глобальным структурам.
Освобождение памяти следует выполнять в функции DllMain при DLL_PROCESS_DETACH, чтобы гарантировать, что все потоки завершили свою работу.
Использование предложенного решения позволит избежать утечек памяти при работе с threadvar в DLL, созданных с помощью Delphi.
Проблема заключается в необходимости корректного освобождения памяти для переменных threadvar при выгрузке DLL в Delphi 2007, чтобы предотвратить утечки памяти.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.