Проблемы порядка завершения модулей в Delphi и ошибки нулевой ссылки: сохранение GlobalLogFactory
При разработке на Delphi часто возникают проблемы, связанные с порядком завершения модулей. Одна из таких проблем связана с использованием глобальных объектов, таких как GlobalLogFactory, которые необходимо корректно освободить, чтобы избежать утечек памяти. В данной статье мы рассмотрим, как обеспечить правильное освобождение глобального объекта журнала в процессе завершения модулей, а также предоставим возможность всем процедурам завершения записывать логи.
Описание проблемы
Разработчик сталкивается с проблемой, когда глобальный объект GlobalLogFactory уничтожается до того, как процедура WebModuleDestroy пытается использовать его для записи лога. Это происходит из-за того, что модуль LogFactory, создающий GlobalLogFactory, включается в модуль MyWebModuleUnit, и его финализация выполняется в обратном порядке.
Контекст
В коде модуля LogFactory создаётся глобальный объект GlobalLogFactory в блоке инициализации, а в блоке финализации он освобождается. Модуль MyWebModuleUnit использует LogFactory для логирования в процедуре WebModuleDestroy. Однако, финализация LogFactory происходит раньше, чем вызов WebModuleDestroy, что приводит к ошибке нулевой ссылки.
unit LogFactory;
...
initialization
GlobalLogFactory := TMyLogFactory.Create;
finalization
FreeAndNil(GlobalLogFactory);
end.
unit MyWebModuleUnit;
...
uses LogFactory;
procedure TMyWebModule.WebModuleDestroy(Sender: TObject);
begin
Assert(Assigned(GlobalLogFactory)); // Ошибка: GlobalLogFactory уже уничтожен
GlobalLogFactory.GetLogger('D:\test.txt').LogLine('test'); // Ошибка нулевой ссылки
end;
Подтверждённый ответ
Чтобы решить проблему, можно явно включить модуль LogFactory в файл DPR как первый модуль. Это обеспечит, что финализация LogFactory будет выполнена после всех необходимых операций по логированию.
Альтернативный ответ
В качестве альтернативного решения можно использовать интерфейс ILogFactory и функцию GlobalLogFactory, которая будет создавать экземпляр TLogFactory по требованию.
unit LogFactory;
interface
type
ILogFactory = interface
function GetLogger(...): TLogger;
end;
TLogFactory = class( TInterfacedObject, ILogFactory )
function GetLogger(...): TLogger;
end;
function GlobalLogFactory: ILogFactory;
implementation
var
_LogFactory: ILogFactory;
function GlobalLogFactory: ILogFactory;
begin
if not Assigned(_LogFactory) then
_LogFactory := TLogFactory.Create;
Result := _LogFactory;
end;
...
// Инициализация и финализация не требуются
В этом случае, интерфейс ILogFactory и связанный с ним объект TLogFactory будут уничтожены автоматически при выгрузке модуля LogFactory, без необходимости явной финализации.
Вывод
Для корректного управления глобальными объектами и обеспечения возможности логирования в процессе завершения работы модулей, разработчикам необходимо тщательно планировать порядок инициализации и финализации модулей. Явное включение модуля LogFactory в DPR или использование интерфейсов для управления жизненным циклом объектов — это два возможных подхода к решению данной проблемы.
Разработчик столкнулся с проблемой корректного освобождения глобального объекта `GlobalLogFactory` в Delphi, когда порядок завершения модулей приводит к ошибке нулевой ссылки.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.