1

我正在运行一个 ISAPI 服务,它运行IdHTTPWebBrokerBridge(用于作为独立 EXE 调试)以及在 Apache 中运行mod_isapi(在生产环境中)。

在销毁 web 模块时记录一些内容时,我发现了以下问题:

unit LogFactory;

...

initialization
  GlobalLogFactory := TMyLogFactory.Create;
finalization
  FreeAndNil(GlobalLogFactory);
end.

-

unit MyWebModuleUnit;

...

uses LogFactory;

procedure TMyWebModule.WebModuleDestroy(Sender: TObject);
begin
  Assert(Assigned(GlobalLogFactory)); // <-- failure
  GlobalLogFactory.GetLogger('D:\test.txt').LogLine('test'); // <-- Nullpointer Exception
end;

LogFactory.pas在初始化时创建对象GlobalLogFactory并在完成时销毁它。

LogFactory.pas:finalization被称为 BEFORE TMyWebModule.WebModuleDestroy,因为它仅包含在本单元中,因此最终确定将以相反的顺序完成。

我怎样才能确保我的GlobalLogFactory将被正确释放(即 FastMM 不会警告内存泄漏),但同时,我想让所有销毁/终结程序有机会记录一些东西?

一种解决方法是LogFactory.pas在 DPR 文件中明确包含作为第一个单元。但我不太喜欢这样,因为这个 Log-Uni​​t 应该在许多项目中使用,并且只需将它包含在需要记录某些内容的单元中就可以使用它。将此日志单元放在每个可能希望在未来记录某些内容的 DPR 中是一项巨大的工作,而忘记它可能会给不知道我做了什么/需要什么的开发人员带来问题。

4

2 回答 2

2

在全局变量中使用类实例的方法是使用接口和函数来获取它。

unit LogFactory;

interface

type
  ILogFactory = interface
    [{GUID}]
    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;

{ TLogFactory Implementation }

initialization

// nothing needed

finalization

// nothing needed

end.

不需要任何initialization或根本不需要finalization

于 2014-06-18T14:00:16.557 回答
0

如果你想

  1. 程序中任何能够记录的单元,以及
  2. 在最终确定期间可用的日志记录,以及
  3. 需要整理的日志代码,

那么你没有很多选择。一种选择是在 .dpr 文件的早期包含日志单元。我不知道你为什么认为这是一个问题。这是实现目标的标准方法。例如,这是外部内存管理器使用的技术。Delphi 开发人员熟悉这个概念。您告诉开发人员他们需要做什么,如果他们不遵循您的指示,程序将无法运行。那是他们的问题。

如果您仍然无法面对这样做,那么我看到了另一种选择。安排在代码中的任何其他初始化之前发生记录器初始化。以及所有其他最终确定之后的最终确定。您可以通过将记录器实现放入与加载时间链接链接的外部模块来做到这一点。

于 2014-06-18T11:49:54.870 回答