Что, как предполагается, происходит при использовании объекта после FreeAndNil?

Я столкнулся с той же проблемой, пытаясь все, комментируя блок пакета исправил проблему для меня

/*bundle {
        language {
            enableSplit = false
        }
        density {
            enableSplit = false
        }
        abi {
            enableSplit = true
        }
    }*/

Я не уверен, что это правильный подход, но после сборки проекта и генерации apk У меня есть файл .aar, который, я думаю, и есть то, что вы пытаетесь получить.

8
задан Rob Kennedy 28 January 2010 в 17:37
поделиться

6 ответов

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

10
ответ дан 5 December 2019 в 04:38
поделиться

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

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 на его переменной, это все еще отпуск неизменная переменная другого кода. Если тот другой код думает, что владеет объектом, то Вы в беде. (Это понятие о владельце не обязательно связывается с TComponent.Owner свойство. Не должно быть объекта, который владеет им; это могла быть общая подсистема Вашей программы.)
  • Не сохраняйте персистентные ссылки на объекты, которыми Вы не владеете. Если Вы не сохраняете долговечные ссылки на объект, то Вы не должны волноваться о том, действительны ли те ссылки все еще. Единственная персистентная ссылка должна быть в коде, который владеет объектом. Любой другой код, который должен использовать тот объект, должен получить ссылку как входной параметр, использовать объект и затем отбросить ссылку, когда это возвращает свой результат.
21
ответ дан 5 December 2019 в 04:38
поделиться

Только усложнить проблему:

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

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

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

8
ответ дан 5 December 2019 в 04:38
поделиться

При установке указателя на ноль Вы не должны мочь использовать его больше. Но если у Вас есть другой указатель на тот же объект, можно использовать его, не получая AV, потому что этот указатель неподвижные точки к объектному адресу а не к нолю.

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

FastMM4 имеет некоторые настройки, которые можно использовать при отладке, который обнаружит такие условия. От FsatMM4Options.inc:

{Устанавливают следующую опцию сделать обширную проверку всех блоков памяти. Все блоки дополнены и заголовком и трейлером, которые используются для проверки целостности "кучи". Освобожденные блоки также очищены к гарантировать, что они не могут быть снова использованы, будучи освобожденным. Эта опция замедляет операции памяти существенно и должна только использоваться для отладки приложения, которое перезаписывает память или снова использует освобожденные указатели. Установка этой опции автоматически включает CheckHeapForCorruption и отключает ASMVersion. Очень важный: при включении этой опции приложение потребует библиотеки FastMM_FullDebugMode.dll. Если эта библиотека не будет доступна, то Вы получите ошибку на запуске.}
{$define FullDebugMode}

Другая кавычка из того же файла:

FastMM всегда ловит попытки освободить тот же блок памяти дважды...

Поскольку Дельфи использует FastMM от Delphi 2007 (2006?), необходимо получить ошибку при попытке к doublefree объекта.

5
ответ дан 5 December 2019 в 04:38
поделиться

Thomas Mueller: Вы попробовали виртуальные методы класса? Конструктор является видом виртуального метода, но Вы называете его против типа - не экземпляр. Это означает, что даже некоторые определенные виртуальные методы не вызовут AV на нулевой ссылке :D

Vegar: Вы не могли быть более правыми! FastMM является лучшим когда-либо когда-либо когда-либо инструмент, который помог мне разыскивающий этот вид ошибок.

1
ответ дан 5 December 2019 в 04:38
поделиться

Блог EureyLog имел отличный пост об этом в апреле 2009 года:

Почему вы всегда должны использовать FreeAndNil вместо Free.

1
ответ дан 5 December 2019 в 04:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: