7

我正在构建一个进行科学模拟的德尔福应用程序。它越来越复杂,现在由许多单元和形式组成。

每次运行时,我都会开始收到 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 的语句并动态创建它们。(除了大部分时间都在使用表格的地方)。一般来说,我使用最小的实用数据类型(字节、短字符串等)并尽量减少“公共”变量和函数的使用

非常欢迎任何提示,布赖恩

4

6 回答 6

12

EOutOfMemory当内存管理器无法为给定的分配请求找到连续的内存块时,就会发生这种情况。因此,您要么 1) 分配比预期更多的内存,2) 泄漏已成功分配的内存,或 3) 分割(不一定泄漏)内存,因此内存管理器必须随着时间的推移不断分配越来越多的内存。

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

于 2012-04-05T16:15:59.687 回答
3

我怀疑您显示的代码是问题的根源。很可能是出现症状的地方。

如果你怀疑你实际上有一些基本的低级损坏,你可能想尝试打开 FastMM 的完全调试模式。例如,您遇到的问题可能是由一般内存堆损坏引起的,而不是实际内存不足。

如果您没有堆损坏,而是真正的内存不足问题,那么查找和解决它通常需要一个适当的工具,称为分析器,如 AQTime。如果您只是简单地调试代码并发现您试图在某个地方或通过对某些内存分配函数的一系列调用中获取不合理数量的内存,那么您的分配代码可能在某种程度上是错误的。

但是,如果没有诸如 nexus quality suite 或 AQTime 或其他类似工具之类的分析器,您将大多是盲目的。您的应用程序只是失败了,堆管理代码报告它内存不足。您可能在某处正在破坏您的堆。您可能真的为 32 位进程分配了太多内存。您的计算机可能没有足够的真实或虚拟内存,或者您正在分配一个巨大的数据结构,但您没有意识到在您的应用程序中是不切实际的。

于 2012-04-05T17:59:16.560 回答
2

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

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

于 2012-04-05T17:48:40.747 回答
2

听起来像内存泄漏。

我总是加一个

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

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

这很好地表明了我构建程序的程度。

于 2012-04-06T11:54:08.597 回答
2

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

如果您没有泄漏,那么您有一个非常极端的碎片问题,您必须通过维护一个对象池而不是继续分配/释放它们来处理它。

于 2012-04-05T17:34:18.850 回答
0

您需要按照“调试”部分中的说明设置项目选项,以便能够调试您的程序。
一旦你这样做了,重新构建你的程序,下次发生错误时,你将能够介入并检查你的代码。使用 Watches (Ctrl+Alt+W),您应该能够看到您分配了多少内存以及分配的位置。

于 2020-03-13T15:49:44.860 回答