2009-07-09 3 views
5

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

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

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

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

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

**Create:** 

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


**Free:** 

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

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


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

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

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

  • Компания FastMM обнаружила ошибку во время операции бесплатного сканирования кадра . Заголовок блока поврежден.

деталь:

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, в том числе "Range Check". Кроме того, FastMM4 настроен на режим супер агрессивной отладки. Без FastMM или вне отладчика программа работает нормально - но все же я знаю, что это не значит, что ошибки больше нет. Фактически он работал (возможно) более одного года, пока я не установил FastMM.


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

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

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

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


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

MyGrid = TStringGrid 
    public 
    AsmJob: TAsmJob; 
    end; 

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

MyGrid.AsmJob=AsmJob; 

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

begin 
    FreeAndNil(AsmJob); 
    inherited 
end; 

ответ

12

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

You should try to use "Range check errors" option (don't forget to make Build, not Compile) and FastMM in full debug mode (with CheckHeapForCorruption, CatchUseOfFreedInterfaces и DetectMMOperationsAfterUninstall options enabled).

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

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

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

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

+0

Спасибо, Александр. Я не имел понятия о «ScanMemoryPoolForCorruptions». Я думаю, это функция, предлагаемая FastMM DLL. Я пойду искать его прямо сейчас. – Ampere

+0

Это функция от стандартного FastMM4.pas. Это из полной автономной версии FastMM. Он не существует в версии FastMM, которая интегрирована в Delphi. Здесь нет DLL. Это просто функция в обычном файле pas;) – Alex

+0

К сожалению, ссылка мертва. Но вы можете получить к нему доступ по адресу: http://web.archive.org/web/20091007162116/http://blog.eurekalog.com/?p=198 – EMBarbosa

4

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

+0

Hi Mason. Нет ASM, без операции с необработанным указателем, проверка диапазона ВСЕГДА включена. Это именно то, что я пытаюсь понять сегодня целый день: где я мог бы переписать этот проклятый объект. – Ampere

+1

Я видел такую ​​ситуацию, как раньше. В конце концов отследил его до сторонней библиотеки, которую я использовал, выполнял некоторые операции с необработанными указателями и искал некоторые из них. Может ли это так? –

+0

Кстати, это не похоже на то, что это не объект, который перезаписывается, а заголовок блока памяти. Но, чтобы быть уверенным, попробуйте поставить точку останова в код очистки, который позволит вам изучить состояние этого объекта до запуска деструктора. Посмотрите на это в отладчике и убедитесь, что его поля действительны. (Если нет, то вы можете использовать точку останова адреса, чтобы найти то, что перезаписывает вашу память тривиально.) –

1

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

Учитывая следующий код:

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; 

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

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

At runtime, a form creates a TStringGrid and then the AsmJob which creates those two SAM objects (and load some data from disk in each of them). The AsmJob is also assigned to the grid. When the form is destroyed, the Grid takes care of the AsmJob by freeing it, which frees the TSam objects. Here is the problem: the first object is freed withot problems but the second one dies when its inherited method (in Destroy destructor) is called.

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

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

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

+0

Привет Райан. Первоначально ObjectList был установлен в OwnObj = true, но теперь я освобождаю объекты «вручную», чтобы увидеть, где появляется ошибка. Вот как я определил, что ошибка появляется в вызове унаследованного (уничтожить) объектов TSam. В любое время! Если я создам и использую объекты TSam без вручную (это означает, что без TAsmJob - который является своего рода менеджером этих объектов), все работает просто замечательно. У меня нет никаких ошибок. -------- PS: У меня уже есть FastMM в полном режиме отладки. – Ampere

2

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

Другим вариантом может быть подкласс кода для добавления к нему журнала - и проверить, будут ли объекты последовательно доступны.