Delphi:如何查找和修复EOutOfMemory错误?

时间:2012-04-05 15:58:45

标签: delphi pascal vcl

我正在构建一个进行科学模拟的delphi应用程序。 它的复杂性越来越高。现在由许多单位和形式组成。

我每次跑步时都会开始出现EOutOFMemory错误。它似乎发生在我在函数中临时使用变量数组期间或之后。有可能提出一个非常愚蠢的问题,是“变种阵列”要求麻烦吗? (我可以将所有内容转换为字符串,但原则上的变体数组可以节省很多捏造的东西)。

违规数组的使用可能是:

 Function  TProject.GetCurrentProjParamsAsArray(LProjectName, LProjectType : ShortString): ArrayOfVariant;
Var
  ArrayIndex : Word;
begin
    SetLength (Result,54);
    ArrayIndex := 0;
    Result [ArrayIndex] := LProjectName;        Inc(ArrayIndex);
    Result [ArrayIndex] := LProjectType;        Inc(ArrayIndex);                   // this structure makes it easier to add extra fields in the DB than hard coding the array index!!
    Result [ArrayIndex] := FileTool.DateTimeForFileNames    ;    Inc(ArrayIndex);
    Result [ArrayIndex] := SiteAndMet.  SiteName            ;    Inc(ArrayIndex);
    Result [ArrayIndex] := SiteAndMet.  PostCode            ;    Inc(ArrayIndex);
    Result [ArrayIndex] := SiteAndMet.  MetFileNamePath     ;    Inc(ArrayIndex);
    Result [ArrayIndex] := SiteAndMet.  SiteLat             ;    Inc(ArrayIndex);
    Result [ArrayIndex] := SiteAndMet.  SiteLong            ;    Inc(ArrayIndex);
    Result [ArrayIndex] := SiteAndMet.  SiteAlt             ;    Inc(ArrayIndex);
    Result [ArrayIndex] := SiteAndMet.  TZoneIndex          ;    Inc(ArrayIndex);
    Result [ArrayIndex] := SiteAndMet.  TZoneHours          ;    Inc(ArrayIndex);
    Result [ArrayIndex] := SiteAndMet.  TZoneMeridian       ;    Inc(ArrayIndex);
    Result [ArrayIndex] := SiteAndMet.  Albedo              ;    Inc(ArrayIndex);
    Result [ArrayIndex] := SiteAndMet.  ArrayTilt           ;    Inc(ArrayIndex);
    Result [ArrayIndex] := SiteAndMet.  ArrayAzimuth        ;    Inc(ArrayIndex);

在任务管理器中 - 峰值内存使用量为42MB,VM为31M,每次运行会出现约90,000页错误。 (在3GB内存的xp机器上)

有没有人有关于监控应用程序中不同组件的内存使用情况的一般提示?或者追踪这个错误的原因?

最近我将主项目数据存储为CSV,使用ADO DB, 与此同时,我也开始使用Variant数据类型,而不是一直转换字符串和单/双。

我已经按照我可以找到的各种内存保存技巧,在实际应用中我删除了Application.CreateForm(TProject,Project);来自.dpr的语句并动态创建它们。 (除非大部分时间都在使用表格)。通常我使用最小的实用数据类型(字节,短串等)并最小化'公共'变量的使用&功能

任何提示非常欢迎,Brian

6 个答案:

答案 0 :(得分:10)

当内存管理器无法为给定的分配请求找到一个有用的内存块时,会发生

EOutOfMemory。因此,您要么1)分配比您预期更多的内存,2)泄漏您已成功分配的内存,或3)分段(不一定泄漏)内存,以便内存管理器必须不断分配越来越多的内存。

发生异常时,请查看调用堆栈。这将导致您无法分配内存的代码。要获取调用堆栈,请在调试器中运行您的应用程序,或使用MadExcept,EurekaLog,JCLExcept等异常日志记录框架。

答案 1 :(得分:2)

您是否安装了FastMem内存管理器的完整版本?它可以帮助您跟踪内存处理中的错误。看看你是否漏了什么东西。

如果您没有泄漏,则会出现非常极端的碎片问题,您必须通过维护对象池来处理它,而不是继续分配/取消分配它们。

答案 2 :(得分:2)

要查找OutOfMemory异常的原因,您需要查看所有对象的创建,而不仅仅是引发异常的位置。

像EurekaLog这样的第三方工具可以显示在应用程序上实例化的所有对象,但没有正确处理。您可以尝试使用带有FreeAndNil过程的try finally块来纠正它们。

答案 3 :(得分:2)

我怀疑你所展示的代码是问题的根源。它可能是一个出现症状的地方。

如果您怀疑自己实际存在一些基本的低级别损坏,则可能需要尝试启用FastMM的完全调试模式。例如,您遇到的问题可能是由于一般内存堆损坏而不是实际耗尽内存造成的。

如果你没有堆损坏,而是有一个真正的内存不足问题,那么找到并解决它通常需要一个合适的工具,称为分析器,如AQTime。如果你只是调试你的代码,你可能会理解你的分配代码是错误的,并且发现某个地方你试图抓住一个不合理的内存量,无论是在一个内部,还是对一些内存分配函数的一系列调用。

然而,如果没有探查器,例如nexus质量套件或AQTime,或其他类似工具,您将大部分失明。您的应用程序只是失败,堆管理代码报告它是内存不足。您可能正在某处破坏堆的地方做某事。您可能真的为32位进程分配了太多内存。您的计算机可能没有足够的实际或虚拟内存,或者您在应用程序中分配了一些您没有意识到的大数据结构。

答案 4 :(得分:2)

听起来像是内存泄漏。

我总是添加一个

  {$IFDEF DEBUG}
    ReportMemoryLeaksOnShutdown := DebugHook <> 0;
  {$ENDIF}

到我的调试版本的项目源文件。

这很好地说明了我构建程序的能力。

答案 5 :(得分:0)

您需要按照“ debugging”部分中的说明设置项目选项,以便能够调试程序。
完成后,重新构建程序,下次发生错误时,您将可以介入并检查您的代码。使用手表(Ctrl + Alt + W),您应该能够看到分配了多少内存以及在哪里。