【问题标题】:Program commiting too much memory [duplicate]程序提交太多内存[重复]
【发布时间】:2011-11-07 14:54:17
【问题描述】:

可能重复:
TStringList of objects taking up tons of memory in Delphi XE

我有一个程序需要一段时间才能运行并使用大量内存(开始时大约 800 mb,结束时大约 1.1 GB)。

我遇到的问题是,即使它使用的内存量很好,但提交的内存量超过 4GB,并给我一个“内存不足”错误。

这是资源监视器的屏幕截图:

占用内存的主要是一个 TStringList 填充了一个对象,该对象具有一堆不同的值和一些字符串列表

有谁知道为什么它提交的内存比我需要的多,我怎样才能让我的程序不这样做?

【问题讨论】:

  • 可能是内存泄漏?
  • 我不确定,当我将对象添加到 TStringList 时,内存(至少是工作内存)会稳步上升,如果我在这样做之后不添加任何对象,它根本不会上升最初。
  • 您使用的是哪个版本的 Delphi?您是否将 FastMM4 用于旧版本的 Delphi?如果没有 - 你应该 - 并使用它的内存泄漏跟踪。
  • 这不是同一个问题:程序使用了大量的工作内存。我将使用量减少了不到一半,所以工作内存很好,但提交的内存是问题。
  • 我使用的是 Delphi 2007,我认为它内置了 FastMM4。除非那是旧版本,我应该使用更新的版本?

标签: delphi memory


【解决方案1】:

提交大小是程序分配的内存量(但不一定在物理内存中)。正如 cmets 中提到的,程序很可能存在内存泄漏(例如,它可能会创建对象但不会删除它们)。所以即使使用的内存量是“合理的”,也不一定代表实际分配​​的数量,而且在 32 位系统中,这个数量“通常”不能超过 4GB。 This question 讨论可能有用的泄漏检测工具。

【讨论】:

    【解决方案2】:

    您的软件可能存在内存泄漏。将这段代码放在程序的“主”块之后(.dpr 文件 - 按 F7 即可到达)。

       {$WARN SYMBOL_PLATFORM OFF}
       ReportMemoryLeaksOnShutdown := DebugHook <> 0;
    

    所以,最终结果应该如下所示:

     begin
      {$WARN SYMBOL_PLATFORM OFF}
      ReportMemoryLeaksOnShutdown := DebugHook <> 0;
    
      Application.Initialize;
      Application.CreateForm(TForm1, Form1);
      Application.Run;
     end.
    

    然后,运行你的程序,直到你得到一些大的内存使用,然后简单地退出它。 Delphi 将显示一个漂亮的窗口,告诉您内存泄漏的大小以及可能发生的一些提示。

    祝你好运!

    【讨论】:

    • 哇,谢谢,这真的很有用。有没有办法查看更多信息或完整的文章?有一堆 Unknown 或 String 意外的小块泄漏,它只是列出了意外泄漏的中大块的大小,而没有说明它们是什么
    • 这可能是您使用 Delphi 提供的工具所能获得的全部内容。有一些商业工具可以提供您正在寻找的反馈。试试这个页面以获得有用的工具列表:delphi.about.com/od/toppicks/tp/aatpmemleak.htm。另外,现在您知道那里发生了内存泄漏。只是找到它的问题。
    • @haole 如果您从 sourceforge 下载 FastMM4,您可以获得完整的内存泄漏报告(包括创建时的堆栈跟踪)。
    • @KingOfKong 也许您在释放所有对象期间发生内存泄漏 - 但问题是在创建对象时分配了这么多内存.有了这个,FastMM4 或其他不会帮助你。如果没有应用的实际代码,很难猜出它有什么问题。
    • @ArnaudBouchez 我们没有代码。他可能会使用在每次迭代中留下的临时东西来搞乱这些对象的创建。 IMO,超出预期的内存太多了,除了粗暴的内存泄漏之外,没有其他任何东西。但是,正如您所指出的,如果没有代码,这只是一个猜测。感谢您提供有关 FastMM4 的提示。
    【解决方案3】:

    您没有显示代码,但这种效果似乎是内存泄漏的结果。
    所以,这个 TStringList(我称之为 parent)有关联的对象,它们有自己的子 TStringLists(我想它只有字符串)。

    执行此内存管理的更简单方法是让 TStringList 为您完成:

    • 如果在 Delphi 版本中您的 TStringList 具有 OwnsObjects 属性,请将其设置为 true。这样,每次调用 DeleteClear 方法都会调用与 parent 列表关联的对象的析构函数 - 即使cll 父母。免费。如果它没有实现,你必须自己做 - 在后代类中覆盖 TStringList 的 Delete、Clear 和 Destroy 方法。
    • 确保子对象的析构函数正确清理在其中创建的对象 - 如果子对象中的字符串列表之一拥有对象,您可以在上述项目中使用相同的策略。

    一个(过于简单的)例子:

    TMyChildObject = class
    private
      fMyListOfMagazineNames, 
      // This one will have TBitmap instances associated with the dogs names
      fMyListOfDogNamesAndPhotos : TStringList;
      fName: String;
    public 
      //[properties, methods, whatever]
    
      property Name: string read fName write fName;
      constructor Create; virtual;
      destructor Destroy; override;
    end;
    
    constructor TMyChildObject.Create;
    begin
      inherited Create;
      fMyListOfMagazineNames = TStringList.Create;
      fMyListOfDogNamesAndPhotos = TStringList.Create; 
      fMyListOfDogNamesAndPhotos.OwnsObjects := True;
    end;
    
    destructor TMyChildObject.Destroy;
    begin
      fMyListOfMagazineNames.Free;
      fMyListOfDogNamesAndPhotos.Free;
      inherited Destroy;
    end;
    

    使用示例:

    var 
      MyObjList: TStringList;
    begin
      MyObjList := TStringList.Create;
      MyObjList.OwnsObjects := True;
    
      // Create your child objects
    
      // And Free them at once 
      MyObjList.Free;
    end;
    

    【讨论】:

    • previous question中出现的所有数据都将被分配和添加。这听起来不像是内存泄漏问题。
    • @ArnaudBouchez:我不知道这个问题。所以这可能是一个重新分配问题?
    • 或分配问题(一些在对象填充期间未释放内存)。
    【解决方案4】:

    正如您在previous question 中所述 - 感谢您选择了一个答案。

    解决问题的主要方法是分配内存中的所有对象。如果您的 28 MB 初始数据消耗超过 1 GB 的内存,那么您就有很多冗余信息。

    你应该这样修改你的算法:

    • 使用 SQL 数据库来处理您的数据而不存在内存问题(使用适当的索引) - 可能是 SQLite3 或嵌入式 Firebird 会很好地工作;
    • 将数据保留在输入文件中,对它们进行内存映射,而不是在内存中分配副本:对每个属性使用 getter 方法,以便即时检索值;
    • 使用 NoSQL 数据库(如 this)插入行可能比 SQL 数据库更快,并且占用更少的磁盘空间和内存;
    • 或者...考虑压缩对象内容(fast compression 是一个不错的选择)。

    【讨论】:

      猜你喜欢
      • 2011-09-20
      • 1970-01-01
      • 2016-12-03
      • 1970-01-01
      • 1970-01-01
      • 2015-12-03
      • 1970-01-01
      • 1970-01-01
      • 2017-09-01
      相关资源
      最近更新 更多