You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FastMM4检测到Quick.Logger内存泄漏,求排查与解决建议

排查与解决Quick.Logger集成DUnitX时的TFileStream内存泄漏问题

排查思路

  • 重复初始化/添加Provider导致资源泄漏:每个测试的Setup都会调用InitializeLogger,将同一个GlobalLogFileProvider重复添加到Logger.Providers中,而TearDown未移除该Provider,导致Logger持续持有Provider引用,其内部的TFileStream无法被正确释放。
  • Provider资源清理不彻底:GlobalLogFileProvider.Stop方法可能未完全释放内部创建的TFileStream对象,仅关闭流但未执行Free操作,导致内存泄漏。
  • 全局单例与测试生命周期不匹配:GlobalLogFileProvider作为全局单例,其生命周期与测试方法的Setup/TearDown不匹配,重复启用/停止可能导致资源未正确回收。

解决建议

  1. 调整Logger初始化时机为全局Fixture级别
    不要在每个测试的Setup中初始化Logger,而是利用DUnitX的[SetupFixture]和[TearDownFixture]特性,在整个测试Fixture启动时初始化一次,结束时清理一次,避免重复操作Provider:

    [TestFixture]
    EncyptionTest = class
      public
        [SetupFixture]
        procedure SetupFixture;
        [TearDownFixture]
        procedure TearDownFixture;
        [Setup]
        procedure Setup;
        [TearDown]
        procedure TearDown;
        // ...测试方法
    end;
    
    procedure EncyptionTest.SetupFixture;
    begin
      InitializeLogger;
    end;
    
    procedure EncyptionTest.TearDownFixture;
    begin
      FinalizeLogger;
    end;
    
  2. 完善FinalizeLogger的清理逻辑
    在清理时先从Logger的Providers集合中移除GlobalLogFileProvider,确保Logger不再持有其引用,再执行停止和释放操作:

    procedure FinalizeLogger; stdcall;
    var
      count: Integer;
      providerIndex: Integer;
    begin
      Log('Logger shutdown', etInfo);
      if Assigned(Logger) then
      begin
        count := Logger.QueueCount;
        Log('There are %d log items in queue.', [count], etInfo);
        // 移除Provider,避免Logger持有引用阻碍释放
        providerIndex := Logger.Providers.IndexOf(GlobalLogFileProvider);
        if providerIndex <> -1 then
          Logger.Providers.Delete(providerIndex);
      end;
    
      if Assigned(GlobalLogFileProvider) then
      begin
        GlobalLogFileProvider.Drain;
        GlobalLogFileProvider.Stop;
        // 若GlobalLogFileProvider为手动创建,需手动释放;单例模式则确认内部资源已清理
        // GlobalLogFileProvider.Free;
        // GlobalLogFileProvider := nil;
      end;
    end;
    
  3. 验证TLogFileProvider的资源释放逻辑
    查看Quick.Logger.Provider.Files.pas的源码,确认Stop方法是否正确释放了内部的TFileStream:

    • 检查Stop方法中是否存在FFileStream.Free; FFileStream := nil;这类代码
    • 如果缺失,可在GlobalLogFileProvider.Stop之后手动释放流(若允许直接访问),或修改Provider源码补充释放逻辑
  4. 避免在收尾阶段触发新的日志操作(可选)
    虽然当前代码中Log调用在Stop之前,但需确保收尾时的日志不会触发Provider的重新初始化,若存在此类情况,可移除收尾时的Log语句,或确保日志操作不会创建新的流资源。

内容的提问来源于stack exchange,提问作者Walter Verhoeven

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 18:27:07