FastMM4 говорит: «Заголовок блока поврежден» - PullRequest
5 голосов
/ 10 июля 2009

У меня была эта неприятная ошибка, которая исчезла в прошлом, но теперь через некоторое время она вернулась.

У меня есть два объекта TSam (производных от TPersistent), созданных и загруженных в объект TAsmJob (производных от TObjectList).

Во время выполнения форма создает TStringGrid, а затем AsmJob, который создает эти два объекта SAM (и загружает некоторые данные с диска в каждый из них). AsmJob также назначен сетке. Когда форма уничтожена, Grid заботится об AsmJob, освобождая его, что освобождает объекты TSam. Вот проблема: первый объект освобождается без проблем, но второй умирает, когда вызывается его унаследованный метод (в деструкторе Destroy).

Я использую FreeAndNil во всей программе, чтобы освободить объекты. Объекты TSam не NIL !!!!! Итак, это первая попытка освободить объекты. Даже данные внутри объектов согласованы.

Основа программы выглядит следующим образом:

**Create:**

Form -> StringGrid
     -> AsmJob -> Sam1, Sam2
StringGrid.AsmJob:= AsmJob;


**Free:**

Form -> StringGrid -> AsmJob -> Sam1, Sam2

Я действительно не понимаю, где я пытаюсь дважды освободить или перезаписать объект ПОСЛЕ того, как он был освобожден.


редактирование:

Некоторые из ошибок, которые я получил:

  • FastMM обнаружил ошибку во время свободная операция сканирования блока. FastMM обнаружил, что блок был изменен после освобождения.

  • FastMM обнаружил ошибку во время свободная операция сканирования блока. Блок заголовок был поврежден.

Detail:

The current thread ID is 0x19C, and the stack trace (return addresses) leading to this error is: 
402E77 [System][@FreeMem] 
4068DC [System][@DynArrayClear] 
405E2D [System][@FinalizeArray] 
405D31 [System][@FinalizeRecord] 
40432F [System][TObject.CleanupInstance] 
404272 [System][TObject.FreeInstance] 
404641 [System][@ClassDestroy] 
4D313E [UnitSam.pas][TSam.Destroy][297] 
4042BF [System][TObject.Free] 
4149ED [SysUtils][FreeAndNil] 
4D9C0A [UnitAsmJob.pas][UnitAsmJob][TAsmJob.Destroy][180]  

У меня все опции "отладки" включены в IDE, включая "Проверка диапазона". Кроме того, FastMM4 настроен на супер агрессивный режим отладки. Без FastMM или вне отладчика программа работает нормально, но я знаю, что это не означает, что ошибки больше нет. На самом деле это работало (возможно) более одного года, пока я не установил FastMM.


редактирование:

Спасибо всем. Нет, я чувствую, что немного двигаюсь в правильном направлении.

Структура программы более сложная. Я предложил только основу, чтобы исходный текст был небольшим. Но какого черта, он уже стал больше :) Таким образом, эти объекты TSam используются для загрузки данных с диска. Один файл в каждом объекте. Они также занимаются обработкой и проверкой данных. Для каждого из этих TSam у меня также есть графический объект, который показывает на экране (графически) данные, содержащиеся в объектах TSam. Каждая строка в TStringGrid также показывает данные в TSam, но в текстовом виде.

У меня один вопрос: если я разобью программу на более мелкие части, чтобы выяснить, где находится ошибка, она все равно появится? Или возможно появиться только в этой конкретной конфигурации?


Ответ на вопрос «как AsmJob назначается TStringGrid, так что TStringGrid уничтожает AsmJob, вы можете показать нам?»

MyGrid = TStringGrid
  public 
    AsmJob: TAsmJob; 
  end; 

затем где-то в TForm.Create (форма, которая содержит Grid), я делаю

MyGrid.AsmJob=AsmJob; 

и в деструкторе MyGrid я делаю:

begin 
  FreeAndNil(AsmJob); 
  inherited 
end;

Ответы [ 4 ]

14 голосов
/ 10 июля 2009

Эта ошибка означает, что ваш код повредил структуры внутренней памяти менеджера. Ваш стек вызовов представляет точку, когда MM обнаружил это. Это не путь ошибки или что-то связанное с этим. Фактическая ошибка происходит ДО этого момента. Это может или не может быть связано с упомянутыми классами.

Вы должны попытаться использовать опцию «Ошибки проверки диапазона» (не забудьте сделать Build, а не Compile) и FastMM в режиме полной отладки (с включенными CheckHeapForCorruption, CatchUseOfFreedInterfaces и DetectMMOperationsAfterUninstall)

Вы также можете включить глобальную переменную FullDebugModeScanMemoryPoolBeforeEveryOperation, чтобы получить ошибку почти сразу после возникновения проблемы, но эта опция замедляет выполнение LOT.

Вероятно, лучший выбор - периодически вызывать ScanMemoryPoolForCorruptions. Звоните в одном месте. Есть ошибка? Позвони раньше. Все еще есть ошибка? Позвони еще раньше. Нет ошибок? Ваша проблема находится где-то между этими последними звонками. Теперь вы можете использовать переменную FullDebugModeScanMemoryPoolBeforeEveryOperation, чтобы получить точное местоположение. Просто включите его только в области кода и выключите сразу после него.

Существует очень похожая ошибка: «FastMM обнаружил, что блок был модифицирован после освобождения». В этом случае ваш код изменяет не внутренние структуры, а другую память, которая вообще не используется («свободная память»).

Кстати, ваша ошибка НЕ ​​является двойной! Если это двойной вызов, FastMM сообщит вам об этом явно (это легко обнаружить, когда вы пытаетесь освободить неиспользуемый или несуществующий блок памяти): «Была предпринята попытка освободить / перераспределить нераспределенный блок ".

4 голосов
/ 10 июля 2009

Повреждение заголовка блока обычно означает, что что-то перезаписывает память, как правило, путем выполнения небезопасной операции. Используете ли вы сырые указатели или ассемблерный код в любой из ваших задач? Кроме того, если у вас отключены проверка диапазона и проверка границ, попробуйте включить их и перестроить. Они могут помочь решить многие проблемы такого рода.

2 голосов
/ 08 марта 2013

Где-то в коде может быть логическая гонка, в которую записывается объект при его освобождении. Добавьте NULL-проверки и другие механизмы IPC (списки блокировок и т. Д.), Чтобы убедиться, что это не так.

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

1 голос
/ 10 июля 2009

Пара вещей, и я спрашиваю, потому что я не вижу ваш код.

С учетом следующего кода:

procedure TForm1.FormCreate(Sender: TObject);
var
   wObjLst : TObjectList;
begin
   wObjLst := TObjectList.Create;
   try
      wObjlst.OwnsObjects := true;
      wObjlst.Add(TPersistent.Create);
      wObjlst.Add(TPersistent.Create);
   finally
      freeandnil(wObjlst);
   end;
end;

Это работает без ошибок.

Вы утверждаете, что

Во время выполнения форма создает TStringGrid, а затем AsmJob, который создает эти два объекта SAM (и загружает некоторые данные с диска в каждом из их). AsmJob также назначен сетке. Когда форма уничтожена, Сетка заботится об AsmJob, освобождая его, что освобождает TSam объекты. Вот проблема: первый объект освобождается без проблем но второй умирает, когда его унаследованный метод (в Destroy деструктор) называется.

Мой первый вопрос: как AsmJob назначается для TStringGrid, так что TStringGrid уничтожает AsmJob, вы можете показать нам?

Во-вторых, зачем создавать потомка TObjectList, чтобы он мог хранить два объекта, а затем освободить их, вместо того, чтобы создавать их самостоятельно и позволить TObjectList уничтожать их, как показано выше.

Другая попытка - это загрузить полный пакет FastMM4 с fastmm.sourceforge.net , установить его и использовать dll fulldebug, чтобы точно определить, в каком объекте произошел сбой. Мы с вами предполагаем, что это один из объектов SAM, и может быть, а может и нет.

...