【问题标题】:How to convince the memory manager to release unused memory如何说服内存管理器释放未使用的内存
【发布时间】:2011-05-27 09:52:07
【问题描述】:

在最近的一篇文章 (My program never releases the memory back. Why?) 中,我展示了在使用 FastMM 时,应用程序不会将大量内存释放回系统。 最近我创建了一个人工测试程序,以确保它不是内存问题,并且它只出现在 FastMM 中。

在这个程序中,我创建和销毁一个对象(与上一篇文章中使用的相同)500 次。

内存要求是(“私有工作集”):

没有 FastMM
运行循环之前:1.2MB
运行循环后:2.1MB

使用 FastMM(积极调试模式)
运行循环之前:2.1MB
运行循环后:25MB

使用 FastMM(发布模式)
运行循环之前:1.8MB
运行循环后:3MB

如果我多次运行循环,内存需求不会增加。这意味着未释放的内存被重新使用,因此这不是内存泄漏(内存泄漏会增加内存占用,每次运行时会增加几个 KB/MB)。


我的问题是:

如何在 FastMM 中禁用此行为?甚至可能吗?我知道,如果我在没有 FastMM 或 FastMM 发布模式的情况下发布程序,它将“浪费”适量的 RAM。但是按需禁用此行为将帮助我(我们?)识别内存泄漏。实际上,在我的第一篇文章(见链接)中,很多人认为我有泄密。显然,正是因为这种行为,才造成了混乱。不,很明显没有泄漏。只是内存管理器拒绝释放大量内存。

它会释放多余的内存吗?什么时候?是什么触发了这个?程序员可以触发吗?例如,当我知道我已经完成了一个 RAM 密集型任务并且用户可能暂时不使用该程序(最小化它)时,我可以将 RAM 刷新回系统吗?当用户打开我的程序的多个实例时会发生什么?他们不会争夺内存吗?

【问题讨论】:

    标签: delphi fastmm


    【解决方案1】:

    您真的不应该将其视为“浪费”内存。将其视为“缓存”未使用的 RAM。内存管理器保留未使用的内存而不是将其释放回操作系统是有原因的,实际上您在问题中已经找到了这个原因。

    你说你一直在循环中重新运行相同的操作。当你这样做时,它仍然有可用的旧内存,它可以立即分配它,而不必向 Windows 请求一个新的堆块。这是将“Fast”置于“FastMM”中的技巧之一,如果不这样做,您会发现程序运行速度要慢得多。

    您无需担心 FastMM 调试模式图。这仅用于调试,您不会发布针对 FullDebugMode 编译的程序。而“不带 FastMM”和“带 FastMM 发布模式”之间的差异大约为 1 MB,这在现代硬件上可以忽略不计。只需额外增加 1 MB 的低成本,您就能获得巨大的性能提升。所以不用担心。

    【讨论】:

    • 嗨梅森。 “...持有未使用的内存而不是出于某种原因将其释放回操作系统” - - - 上帝!我不是在争论缓存的好处!!!我知道缓存很好!但我想对其进行一些控制——至少出于调试目的。知道您的应用程序需要的确切 RAM 量不是很好吗? :)
    • “只需额外增加 1 MB 的低成本,就可以大幅提升性能” - - - 这是我一次创建/销毁一个对象时“浪费”的 RAM 量( 500 次)。但是如果我加载 500 个对象然后将它们全部释放,那么未释放的 RAM 量(由 FastMM 提供)是相当可观的! Borland 的内存管理器会立即返回大部分 RAM!具有 1 GB RAM EEEPC 和 Windows 7 的用户将无法启动我的程序的第二个实例,即使第一个实例由于没有释放内存而处于空闲状态。
    【解决方案2】:

    使 FastMM 快速的部分原因在于它会分配一大块内存并从中分割出更小的统一大小的块。如果块的任何部分正在使用中,则不能将其释放回操作系统。

    欢迎您使用不同的内存管理器。一种方法是将所有分配直接路由到VirtualAlloc。分配将被四舍五入一次占据整个页面,因此如果您有很多小分配,您的程序可能会受到影响,但是当您调用VirtualFree时,您可以确信内存绝对不属于您的程序没有了。

    另一种选择是将所有内容路由到操作系统堆。使用HeapAlloc。您甚至可以为您的程序启用the low-fragmentation heap(Windows Vista 中默认启用),这将使操作系统采用类似于 FastMM 使用的策略,但它允许您使用 Microsoft 的一些调试和分析工具随着时间的推移跟踪程序的内存使用情况。但请注意,在您调用 HeapFree 后,某些指标可能仍会将内存显示为属于您的程序。

    此外,工作集指的是当前在物理 RAM 中的内存。您观察到数字上升并不意味着您的程序分配了更多内存。这可能只是意味着您的程序触及了一些它之前分配但尚未放入 RAM 的内存。在您的循环中,您触及了该内存,而操作系统尚未决定将其分页回磁盘。

    【讨论】:

      【解决方案3】:

      我使用以下作为内存管理器。我这样做是因为它在线程争用下的性能比 FastMM 好得多,而 FastMM 实际上相当差。我知道像Hoard 这样的可扩展管理器会更好,但这很适合我的需求。

      unit msvcrtMM;
      
      interface
      
      implementation
      
      type
        size_t = Cardinal;
      
      const
        msvcrtDLL = 'msvcrt.dll';
      
      function malloc(Size: size_t): Pointer; cdecl; external msvcrtDLL;
      function realloc(P: Pointer; Size: size_t): Pointer; cdecl; external msvcrtDLL;
      procedure free(P: Pointer); cdecl; external msvcrtDLL;
      
      function GetMem(Size: Integer): Pointer;
      begin
        Result := malloc(size);
      end;
      
      function FreeMem(P: Pointer): Integer;
      begin
        free(P);
        Result := 0;
      end;
      
      function ReallocMem(P: Pointer; Size: Integer): Pointer;
      begin
        Result := realloc(P, Size);
      end;
      
      function AllocMem(Size: Cardinal): Pointer;
      begin
        Result := GetMem(Size);
        if Assigned(Result) then begin
          FillChar(Result^, Size, 0);
        end;
      end;
      
      function RegisterUnregisterExpectedMemoryLeak(P: Pointer): Boolean;
      begin
        Result := False;
      end;
      
      const
        MemoryManager: TMemoryManagerEx = (
          GetMem: GetMem;
          FreeMem: FreeMem;
          ReallocMem: ReallocMem;
          AllocMem: AllocMem;
          RegisterExpectedMemoryLeak: RegisterUnregisterExpectedMemoryLeak;
          UnregisterExpectedMemoryLeak: RegisterUnregisterExpectedMemoryLeak
        );
      
      initialization
        SetMemoryManager(MemoryManager);
      
      end.
      

      这不是您的问题的答案,但它太长了,无法放入评论中,您可能会发现针对此 MM 运行您的应用程序很有趣。我的猜测是它的执行方式与 FastMM 相同。

      【讨论】:

        【解决方案4】:

        已解决

        按照 Barry Kelly 的建议,FastaMM 将自动释放内存。 为了确认这一点,我创建了第二个分配大量 RAM 的程序。一旦 Windows 用完 RAM,我的程序内存利用率就会恢复到原来的值。

        问题解决了。 谢谢巴里。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-05-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-03-21
          相关资源
          最近更新 更多