В статье рассматривается важный аспект программирования на Delphi, связанный с управлением памятью при работе со словарями объектов. Особое внимание уделяется проблеме утечек памяти, которые могут возникать при неправильном освобождении объектов, добавленных в коллекции.
Проблема утечек памяти
При работе с коллекциями объектов в Delphi важно понимать, что объекты хранятся не по значению, а по ссылке (указателю или ссылке). Это означает, что при добавлении объекта в коллекцию, например, в TObjectDictionary, происходит не копирование объекта, а установка ссылки на него. Следовательно, если вы попытаетесь освободить объект после его добавления в коллекцию, вы убьете ссылку и коллекция будет содержать "висячую" ссылку, что приведет к утечке памяти.
В приведенном выше коде создается объект myPOI, который затем добавляется в словарь PoiDict. После добавления в коллекцию происходит вызов myPOI.Free, который освобождает память, выделенную под объект, и коллекция начинает хранить уже несуществующий объект, что ведет к утечке.
Использование TObjectDictionary с передачей владения
Чтобы избежать подобных проблем, следует использовать TObjectDictionary, который позволяет передать владение над объектом коллекции, что позволяет ей самостоятельно управлять жизненным циклом объекта.
function TForm2.CreateOrUpdate(username: String; NewTimestamp: TDateTime): String;
var
poiTimeStamp: TDateTime;
myPOI: TMyPOI;
Index: Integer;
begin
if PoiDict.TryGetValue(username, myPOI) then
begin
// Обновление существующего объекта
Result := IntToStr(myPOI.Value) + ' ' + DateTimeToStr(myPOI.Timestamp);
poiTimestamp := myPOI.Timestamp;
// Изменение свойства объекта напрямую изменит его в словаре
myPOI.Timestamp := NewTimeStamp;
end
else
begin
// Добавление нового объекта
Index := Random(999);
Result := IntToStr(Index) + ' ' + DateTimeToStr(NewTimeStamp);
myPOI := TMyPOI.Create;
try
myPOI.Value := Index;
myPOI.Timestamp := NewTimeStamp;
PoiDict.Add(username, myPOI);
except
on E: Exception do
begin
myPOI.Free;
raise;
end;
end;
end;
end;
initialization
PoiDict := TObjectDictionary<string, TMyPOI>.Create([doOwnsValues]);
finalization
PoiDict.Free;
Проверка на исключения
В данном коде также предусмотрен блок except, который обрабатывает возможные исключения при добавлении объекта в словарь, освобождая объект в случае ошибки, чтобы избежать утечек памяти.
Заключение
При работе с коллекциями в Delphi важно понимать, что после добавления объекта в коллекцию, которая поддерживает владение объектами, освобождение этого объекта может привести к утечкам памяти. Использование TObjectDictionary с включенным режимом владения позволяет избежать ручного управления памятью и автоматически освобождает объекты при удалении коллекции.
Управление памятью в Delphi при работе со словарями объектов требует внимательного обращения с объектами, чтобы избежать утечек из-за неправильного освобождения ссылок.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.