Всегда неправильно использовать методы или свойства нулевой ссылки, даже если она работает иногда.
FreeAndNil
действительно не может использоваться для обнаружения двойных разрядов. Можно безопасно позвонить FreeAndNil
по уже нулевой переменной. Так как это безопасно, это не поможет вам ничего обнаружить.
Это не ошибка устаревших указателей. Это ошибка с нулевой ссылкой. Ошибка устаревшего указателя - это когда вы освободили объект, но не очистили все переменные, на которые он ссылался. Затем переменная по-прежнему содержит старый адрес объекта. Это очень трудно обнаружить. Вы можете получить такую ошибку, как это:
MStr := TMemoryStream.Create;
MStr.Free;
MStr.Size := 0;
Вы также можете получить так:
MStr := TMemoryStream.Create;
OtherStr := MStr;
FreeAndNil(MStr);
OtherStr.Size := 0;
Использования MStr.Size
после того как вы освободили объект MStr
ссылки ошибка, и она должна поднять исключение. Будет ли это Поднять исключение зависит от реализации. Может быть, так и будет, а может и нет. Однако это не случайно.
Если вы ищете ошибку двойного доступа, вы можете использовать вспомогательные средства для отладки, которые предоставляет FastMM, как и другие. Он работает, фактически не освобождая память обратно в операционную систему, или даже обратно в внутренний пул свободной памяти Delphi. Вместо этого он записывает известные плохие данные в пространство памяти объекта, поэтому, когда вы видите эти значения, вы будете знать, что читаете из того, что вы уже освободили. Он также изменяет VMT объекта таким образом, что в следующий раз, когда вы вызываете виртуальный метод на эту ссылку на объект, вы получите предсказуемое исключение, и оно даже скажет вам, какой предположительно освобожденный объект вы пытались использовать. Когда вы снова попытаетесь освободить объект, он может сказать вам не только о том, что вы уже освободили его, но и о том, где он был освобожден в первый раз (со стеком) и где он был выделен.Он также собирает эту информацию для сообщения об утечках памяти, где вы освободили объект меньше, чем один раз, а не больше.
Есть также привычки, которые вы можете использовать, чтобы избежать проблемы для будущего кода:
- Сократить использование глобальных переменных. Глобальная переменная может быть изменена любым кодом во всей программе, заставляя вас удивляться всякий раз, когда вы ее используете: «Является ли значение этой переменной все еще действительным или еще какой-то другой код освободил его?» Когда вы ограничиваете область действия переменной, вы уменьшаете количество кода, которое вы должны учитывать в своей программе, если ищете причины, по которым переменная не имеет ожидаемого значения.
- Будьте предельно понятны, кто владеет объектом. Когда есть два фрагмента кода, которые имеют доступ к одному и тому же объекту, вам нужно знать, какая из этих частей кода владеет объектом. Каждый из них может иметь другую переменную для ссылки на объект, но есть еще один объект. Если одна часть кода вызывает
FreeAndNil
на свою переменную, это все равно оставляет неизменной переменную другого кода. Если этот другой код считает, что он владеет объектом, тогда у вас проблемы. (Эта концепция владельца не обязательно привязана к свойству. Не нужно иметь объект, которому это принадлежит, это может быть общая подсистема вашей программы.)
- Не оставляйте постоянные ссылки на объектов, которые у вас нет. Если вы не держите долгоживущие ссылки на объект, вам не нужно беспокоиться о том, остаются ли эти ссылки действительными. Единственная постоянная ссылка должна быть в коде, которому принадлежит объект. Любой другой код, который должен использовать этот объект, должен получить ссылку в качестве входного параметра, использовать объект, а затем отказаться от ссылки, когда он вернет свой результат.
Я думаю, что «кто-то» не хватает некоторых важных понятий. – 2008-12-12 22:11:17
Как я уже говорил, у FastMM есть опция, которая делает то, что вы описываете. Роб указывает, что он перезапишет память «магическими числами», чтобы обнаружить такие ошибки. Взгляните на это. Загрузите полный FastMM4 и включите ведение журнала в файл. Я нашел это весьма полезным. – Vegar 2008-12-14 21:08:45
FreeAndNil() не заполняет память, занятую экземпляром, она игнорирует переданную ссылку. – Bevan 2008-12-30 21:05:14