2012-04-11 3 views
8

Я не могу показаться, чтобы это было видно. Моя программа компилируется и запускается успешно, но во время отладки только она выдает окно с сообщением «Invalid Pointer Operation» при выключении программы. Я тщательно проверил все события FormCloseQuery и FormDestory для любого синтаксиса или логической ошибки. Я не нашел их, и они выполняются так, как ожидалось, без какой-либо ошибки.Недействительная операция указателя - Delphi XE

enter image description here

Когда я говорю компилятор разорвать на ошибку Invalid Pointer Operation, он ничего не делает, но вешает программу. В этот момент мне пришлось прекратить или убить процесс.

Как вы оцениваете это?

Спасибо заранее,

+6

Включите Debug DCU и пройдите через выключение, пока не найдете, что вызывает эту ошибку. Вы работаете с FastMM в режиме полной отладки? –

+0

@DavidHeffernan, :) Помню, у нас был разговор о FastMM. К сожалению, я не использовал FastMM, так как я тестировал его во время работы. Я включу DCU и посмотрю, что произойдет. – ThN

+0

@DavidHeffernan, после перерыва с включенным dcu, отладчик остановился в файле System.pas. Немного сбивает с толку, но я думаю об этом, потому что одна из причин, по которой он ведет машину Мейсона. Думаю, теперь мне нужно снова поставить FastMM. – ThN

ответ

25

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

Наиболее распространенным является то, что вы пытаетесь освободить объект, который вы уже освободили. Если вы включите FullDebugMode от FastMM, он обнаружит это и сразу укажет на проблему. (Но обязательно создайте файл карты, чтобы у него была информация, необходимая для создания полезных трассировок стека.)

Второй способ: если вы пытаетесь освободить память, которая была выделена где-то, кроме менеджера памяти , Я видел это несколько раз, когда передавал строку из Delphi EXE в DLL Delphi, которая не использовала функцию диспетчера разделяемой памяти.

И третий способ включает в себя беспорядок с указателями напрямую и, вероятно, не относится к вам. Если вы попробуете FreeMem или Dispose плохой указатель, который не ссылается на фактический блок памяти, выделенный FastMM, вы получите эту ошибку.

Это, скорее всего, первый. Используйте FullDebugMode, и вы легко найдете источник проблемы.

+0

вы абсолютно правы. Ваша первая причина в том, почему моя программа поднимает это уведомление об исключениях. Тем не менее, он поднимается, потому что мое событие уничтожения TForm вызывается более одного раза. Этого я не понимаю, почему. – ThN

+0

Если бы я мог предположить, я бы сказал, потому что ваша форма была создана с владельцем (например, приложение, вы использовали 'Application.CreateForm' для ее создания?), А затем где-то еще вы пытаетесь ее освободить вручную. Взгляните на следы стека за два раза, когда он освобождается; они дадут вам представление о том, что происходит. И сохраните [Принцип единоличного владения] (http://tech.turbu-rpg.com/106/delphi-memory-management-made-simple): ваши формы могут принадлежать Приложению или вашим кодом, но а не обоими. –

0

Я был пойман этим типом «указанной ошибки» во время отладки Delphi.

Проверьте, есть ли у вас какие-либо наблюдаемые переменные с включенными функциями «Разрешить функциональные вызовы» или часы, которые пытаются показать другие переменные в одном и том же подразделении (или глобальном), которые могут быть неинициализированы. При остановке в точке останова это может привести к тому, что отладчик Delphi попытается отобразить значение через вызов функции, который обращается к неинициализированному указателю или переменной. Фактическая переменная, которая приводит к тому, что AV-файл не включен в ваш список наблюдения.

+3

EAccessViolation отличается от EInvalidPointer. * Доступ к * недопустимый указатель дает первое; только * освобождение * дает последнее. –

9

Неверные операции указателя происходят, когда вы сообщаете диспетчеру памяти Delphi освободить память, которая не принадлежит ему. Возможны три способа:

  • Освобождение указателя или объекта, который уже освобожден.
  • Использование FreeMem, чтобы освободить то, что было выделено другим менеджером памяти (например, GlobalAlloc или CoTaskMemAlloc).
  • Освобождение неинициализированного указателя. (Это отличает освобождение нулевого указателя, который полностью безопасен.)

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

Такие инструменты, как MadExcept и Eureka Log, могут помочь вам найти ошибки с двойным освобождением. Они могут отслеживать, где был указан выделенный указатель, и где он был освобожден в первый раз, и это иногда достаточно информации для выяснения вашей ошибки и прекращения освобождения вещей несколько раз.

+0

Это также выбрасывается, если вы попытаетесь освободить адрес локально объявленного объекта? – Wolf

+0

Да, @ Волк. Это покрывается второй маркой. В этом случае вы пытаетесь освободить память, выделенную в стеке. –

+0

Спасибо. Этот «выделенный» или «диспетчер памяти» выглядит странно, когда речь идет об автоматических переменных. Может быть, это тоже нужно добавить (более явным образом)? – Wolf

1

4-я причина неправильной операции указателя. У меня было два указателя, где массив [0..1000] реального и третьего указателя, который был массивом [1..200] реального. Все 3 указателя, где инициализированы для i: от 0 до 1000, begin ptr1^[i]: = 0; ptr2^[i]: = 0; ptr3^[i]: = 0; конец; Хотя эта плохая программа не беспокоила Паскаля в Delphi, вызов Dispose из любого из 3 указателей привел к неправильной операции указателя. Исправление было просто для правильной инициализации 3-го указателя.

Смежные вопросы