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

时间:2022-04-29 17:08:13

I'm building a delphi application which does scientific simulation. It's growing in complexity & now consists of many units and forms.

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

I'm starting to get EOutOFMemory Errors each time I run. It seems to happen during or just after I use an Array of variant temporarily within a functions. At risk of asking a really dumb question, is "array of variant" asking for trouble? ( I could convert everything to string, but array of variant in principle saves a lot of fudging things).

每次运行时,我都开始出现EOutOFMemory错误。它似乎是在我在一个函数中临时使用一个变量数组时发生的。冒着问一个非常愚蠢的问题的风险,是“一系列的变体”自找麻烦吗?(我可以把所有的东西都转换成字符串,但是在原则上,数组的变体可以节省很多东西)。

the offending array use might be:

违规的数组使用可能是:

 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);

In task manager - peak memory usage is 42MB, VM is 31M and I'm getting ~90,000 page faults per run. (on an xp machine with 3GB ram)

在任务管理器中——峰值内存使用量是42MB, VM是31M,每次运行时,我将得到9万页的错误。(在一台带有3GB内存的xp机器上)

Does anyone have any general tips on monitoring memory usage by the different components within my application? or on tracing the cause of this error?

在我的应用程序中,是否有人有关于监控内存使用的一般技巧?或者追踪这个错误的原因?

Recently I've gone from storing the main project data as CSV to using ADO DBs, At the same time I've also begun using the Variant data type rather than converting betweem string and single/double all the time.

最近,我从将主要项目数据存储为CSV到使用ADO DBs,同时我也开始使用变量数据类型,而不是一直转换字符串和单/double。

i've followed various memory saving tips I can find like, where practical I've removed the Application.CreateForm(TProject, Project); statements from the .dpr And creating them dynamically. (except where the forms are being used most of the time anyway). Generaly I use smallest practical datatype (byte, shortstring, etc) and minimise use of 'public' variables & functions

我已经遵循了一些我可以找到的节省内存的技巧,在实践中我已经删除了应用程序。CreateForm(TProject、项目);来自.dpr的语句并动态地创建它们。(除了这些表格大部分时间都在使用)。一般来说,我使用最小的实用数据类型(字节、短字符串等),并尽量减少“公共”变量和函数的使用。

any tips very welcome, Brian

欢迎任何建议,布莱恩。

5 个解决方案

#1


2  

I doubt that the code you are showing, is the source of the problem. It is probably a place where a symptom occurs.

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

If you suspect that you have in fact, some basic low level corruption, you might want to try turning on FastMM's Full Debug Mode. For example, problems like the one you're encountering could be caused by general memory heap corruption instead of actually running out of memory.

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

If you do not have heap corruption, but instead have a true out of memory problem, then finding and solving it usually requires a proper tool, called a profiler, like AQTime. Perhaps your allocation code is wrong in a way you can understand if you simply debug your code, and find that somewhere you are trying to grab an unreasonable amount of memory, either in one, or a series of calls to some memory-allocation function.

如果您没有堆损坏,而是有一个真正的内存问题,那么查找和解决它通常需要一个合适的工具,称为分析器,像AQTime。也许您的分配代码是错误的,您可以理解,如果您只是调试您的代码,并且发现您试图在某个地方获取不合理的内存数量,或者是一个,或者是一系列的调用内存分配函数。

However, without a profiler, such as nexus quality suite or AQTime, or another similar tool, you will be mostly blind. Your application is simply failing and the heap management code is reporting it is out of memory. It is possible that you are doing something somewhere that is corrupting your heap. It is possible you are really allocating too much memory for your 32 bit process. It is possible your computer does not have enough real or virtual memory, or that you are allocating a huge data structure that you have not realized is not practical, within your application.

但是,如果没有一个分析器,比如nexus质量套件或AQTime,或者其他类似的工具,你将会几乎失明。您的应用程序只是失败,堆管理代码报告它已经内存不足。有可能你正在做某件事,正在腐蚀你的堆。你可能真的为你的32位进程分配了太多的内存。您的计算机可能没有足够的真实或虚拟内存,或者您正在分配一个您没有实现的巨大的数据结构,在您的应用程序中是不实际的。

#2


10  

EOutOfMemory occurs when the memory manager cannot find a contigious block of memory for a given allocation request. So you are either 1) allocating more memory than you are expecting, 2) leaking memory you have successfully allocated, or 3) fragmenting (not necessarily leaking) memory so the memory manager has to keep allocating more and more memory over time.

当内存管理器无法为给定的分配请求找到一个连续的内存块时,就会发生EOutOfMemory。因此,您要么是分配了比预期更多的内存,2)内存泄漏已经成功分配,或3)分割(不一定是泄漏)内存,这样内存管理器就必须不断分配更多内存。

When the exception occurs, look at the call stack. That will lead you to the code that is failing to allocate memory. To get the call stack, run your app in the debugger, or use an exception logging framework like MadExcept, EurekaLog, JCLExcept, etc.

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

#3


2  

Have you installed the full version of the FastMem memory manager? It can help you track down errors in memory handling. See if you're leaking something.

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

If you don't have a leak you have a pretty extreme fragmentation problem, you'll have to deal with it by maintaining a pool of objects rather than keeping allocating/deallocating them.

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

#4


2  

To find a cause of OutOfMemory exceptions you need to look on all objects creation and not just where the exception are raised.

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

A third part tool like EurekaLog can show you all objects instantiated on application and not correctly disposed. You can try to correct they using try finally blocks with FreeAndNil procedure.

像EurekaLog这样的第三部分工具可以显示所有在应用程序上实例化的对象,并且没有正确处理。你可以试着修正它们,最后使用FreeAndNil程序。

#5


2  

Sounds like memory leaks.

听起来像内存泄漏。

I always add a

我总是添加一个

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

to the project source file for my debug builds.

为我的调试构建的项目源文件。

This gives a good indication of how well I've built the program.

这很好地说明了我是如何构建这个程序的。

#1


2  

I doubt that the code you are showing, is the source of the problem. It is probably a place where a symptom occurs.

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

If you suspect that you have in fact, some basic low level corruption, you might want to try turning on FastMM's Full Debug Mode. For example, problems like the one you're encountering could be caused by general memory heap corruption instead of actually running out of memory.

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

If you do not have heap corruption, but instead have a true out of memory problem, then finding and solving it usually requires a proper tool, called a profiler, like AQTime. Perhaps your allocation code is wrong in a way you can understand if you simply debug your code, and find that somewhere you are trying to grab an unreasonable amount of memory, either in one, or a series of calls to some memory-allocation function.

如果您没有堆损坏,而是有一个真正的内存问题,那么查找和解决它通常需要一个合适的工具,称为分析器,像AQTime。也许您的分配代码是错误的,您可以理解,如果您只是调试您的代码,并且发现您试图在某个地方获取不合理的内存数量,或者是一个,或者是一系列的调用内存分配函数。

However, without a profiler, such as nexus quality suite or AQTime, or another similar tool, you will be mostly blind. Your application is simply failing and the heap management code is reporting it is out of memory. It is possible that you are doing something somewhere that is corrupting your heap. It is possible you are really allocating too much memory for your 32 bit process. It is possible your computer does not have enough real or virtual memory, or that you are allocating a huge data structure that you have not realized is not practical, within your application.

但是,如果没有一个分析器,比如nexus质量套件或AQTime,或者其他类似的工具,你将会几乎失明。您的应用程序只是失败,堆管理代码报告它已经内存不足。有可能你正在做某件事,正在腐蚀你的堆。你可能真的为你的32位进程分配了太多的内存。您的计算机可能没有足够的真实或虚拟内存,或者您正在分配一个您没有实现的巨大的数据结构,在您的应用程序中是不实际的。

#2


10  

EOutOfMemory occurs when the memory manager cannot find a contigious block of memory for a given allocation request. So you are either 1) allocating more memory than you are expecting, 2) leaking memory you have successfully allocated, or 3) fragmenting (not necessarily leaking) memory so the memory manager has to keep allocating more and more memory over time.

当内存管理器无法为给定的分配请求找到一个连续的内存块时,就会发生EOutOfMemory。因此,您要么是分配了比预期更多的内存,2)内存泄漏已经成功分配,或3)分割(不一定是泄漏)内存,这样内存管理器就必须不断分配更多内存。

When the exception occurs, look at the call stack. That will lead you to the code that is failing to allocate memory. To get the call stack, run your app in the debugger, or use an exception logging framework like MadExcept, EurekaLog, JCLExcept, etc.

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

#3


2  

Have you installed the full version of the FastMem memory manager? It can help you track down errors in memory handling. See if you're leaking something.

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

If you don't have a leak you have a pretty extreme fragmentation problem, you'll have to deal with it by maintaining a pool of objects rather than keeping allocating/deallocating them.

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

#4


2  

To find a cause of OutOfMemory exceptions you need to look on all objects creation and not just where the exception are raised.

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

A third part tool like EurekaLog can show you all objects instantiated on application and not correctly disposed. You can try to correct they using try finally blocks with FreeAndNil procedure.

像EurekaLog这样的第三部分工具可以显示所有在应用程序上实例化的对象,并且没有正确处理。你可以试着修正它们,最后使用FreeAndNil程序。

#5


2  

Sounds like memory leaks.

听起来像内存泄漏。

I always add a

我总是添加一个

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

to the project source file for my debug builds.

为我的调试构建的项目源文件。

This gives a good indication of how well I've built the program.

这很好地说明了我是如何构建这个程序的。