Delphi: как найти и исправить ошибку EOutOfMemory?

Я создаю приложение delphi, которое выполняет научное моделирование. Он растет в сложности и теперь состоит из многих единиц и форм.

Я начинаю получать ошибки EOutOFMemory каждый раз, когда я запускаю. Кажется, это происходит во время или сразу после того, как я временно использую массив variant в функциях. Рискуя задать действительно глупый вопрос," массив вариантов " просит неприятностей? ( Я мог бы преобразовать все в строку, но массив variant в принципе экономит много fudging things).

использование оскорбительного массива может быть:

 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 ошибок страницы за запуск. (на машине xp с ОЗУ 3GB)

есть ли у кого-нибудь общие советы по мониторингу использования памяти различными компонентами в моем приложении? или об отслеживании причины этой ошибки?

недавно я перешел от хранения основных данных проекта как CSV к использованию ADO DBs, В в то же время я также начал использовать тип данных Variant вместо преобразования строки betweem и single/double все время.

Я следил за различными советами по экономии памяти, которые я могу найти, как, где практично я удалил приложение.CreateForm (TProject, Project); операторы из .ДНР и создавать их динамически. (за исключением тех случаев, когда формы используются большую часть времени). Обычно я использую наименьший практический тип данных (байт, короткая строка и т. д.) и минимизирую использование "public" переменные и функции

любые советы очень приветствуются, Брайан

5 ответов


Я сомневаюсь, что код, который вы показываете, это источник проблемы. Вероятно, это место, где возникает симптом.

Если вы подозреваете, что у вас есть на самом деле, некоторые базовые низкоуровневые повреждения, вы можете попробовать включить режим полной отладки FastMM. Например, проблемы, подобные той, с которой вы столкнулись, могут быть вызваны общим повреждением кучи памяти, а не фактическим исчерпанием памяти.

Если у вас нет кучи коррупции, но вместо этого правда из проблемы с памятью, а затем найти и решить ее, как правило, требует надлежащего инструмента, называется профилировщик, как AQTime. Возможно, ваш код распределения ошибочен таким образом, что вы можете понять, если вы просто отлаживаете свой код и обнаруживаете, что где-то вы пытаетесь захватить необоснованный объем памяти, либо в одном, либо в серии вызовов какой-то функции распределения памяти.

однако без профилировщика, такого как nexus quality suite или AQTime, или другого подобного инструмента, вы будете в основном слепой. Ваше приложение просто терпит неудачу, и код управления кучей сообщает, что у него нет памяти. Возможно, вы где-то делаете что-то, что развращает вашу кучу. Возможно, вы действительно выделяете слишком много памяти для своего 32-битного процесса. Возможно, ваш компьютер не имеет достаточно реальной или виртуальной памяти, или что вы выделяете огромную структуру данных, которую вы не поняли, не практично, в вашем приложении.


EOutOfMemory происходит, когда диспетчер памяти не может найти смежный блок памяти для данного запроса на выделение. Таким образом, вы либо 1) выделяете больше памяти, чем ожидаете, 2) утечка памяти, которую вы успешно выделили, либо 3) фрагментируете (не обязательно утечка) память, поэтому менеджер памяти должен продолжать выделять все больше и больше памяти с течением времени.

когда возникает исключение, посмотрите на стек вызовов. Это приведет вас к коду, который не удается выделить память. Чтобы получить стек вызовов, запустите приложение в отладчике или используйте структуру регистрации исключений, такую как MadExcept, EurekaLog, JCLExcept и т. д.


вы установили полную версию fastmem memory manager? Это может помочь вам отслеживать ошибки в обработке памяти. Посмотри, не течет ли что-нибудь.

Если у вас нет утечки, у вас есть довольно экстремальная проблема фрагментации, вам придется иметь дело с ней, поддерживая пул объектов, а не сохраняя их выделение/освобождение.


чтобы найти причину исключений OutOfMemory, вам нужно посмотреть на создание всех объектов, а не только на то, где возникает исключение.

инструмент третьей части, такой как EurekaLog, может показать вам все объекты, созданные в приложении и неправильно расположенные. Вы можете попробовать исправить их, используя try finally блоки с процедурой FreeAndNil.


звучит как утечка памяти.

Я всегда добавляю

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

в исходный файл проекта для моей отладочной сборке.

Это дает хорошее представление о том, как хорошо я построил программу.