Проблема с отладкой Xcode и ARC (пропуск освобождения)

#xcode #debugging #instruments #dealloc #automatic-ref-counting

#xcode #отладка #инструменты #освобождение #автоматический подсчет ссылок

Вопрос:

Я потратил некоторое время на отладку странной проблемы с ARC и пользовательскими функциями освобождения.

  1. Я создаю подкласс NSOperation class
  2. Я установил блок завершения для этой операции
  3. На операцию ссылается сильное свойство очень плоского объекта (нет методов, автоматических ивар, два сильных свойства), позволяет вызвать этот объект DataRequest
  4. следуя всем рекомендациям, блок завершения использует только слабые ссылки на локальные объекты (включая саму операцию)
  5. ни компилятор, ни анализатор не создают никаких проблем
  6. DataRequest содержит ЕДИНСТВЕННУЮ ссылку на операцию, которую я создаю, и уничтожается в блоке завершения операции. Он ВСЕГДА уничтожается ( dealloc всегда выполняется)
  7. Моя операция имеет обычай dealloc . В нем есть только один вызов NSLog.

… и проблема в том:

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

Если я запускаю это в инструментах, все в порядке, системная консоль печатает сообщение, а инструмент распределения сообщает, что операция освобождается от правильного снимка стека, включая пользовательский dealloc. Утечек не обнаружено.

Я на 100% уверен, что использую одни и те же настройки компилятора для отладки и профилирования.

Самое запутанное в конце: если я создаю пользовательскую версию [DataRequest dealloc] и добавляю self.operation = nil; к ней — все работает нормально даже из отладчика.

Есть ли у кого-нибудь какие-нибудь подсказки, какие параметры компоновщика компилятора можно попытаться увидеть какую-то разницу? может ли это быть ошибкой в инструментах Apple (все мы были в положении, обвиняя крупную рыбу в наших собственных ошибках, верно?)

… и да, я пробовал с GDB и LLDB. Результат был тот же — что может что-то указывать.

Я попытался создать минималистичный образец, но он просто сработал (действительно) 😉

Спасибо

Комментарии:

1. Я сделал очень простое наблюдение … если я запускаю приложение на симуляторе из XCode (GDB или LLDB), мои сообщения журнала dealloc не печатаются. Если я просто выхожу из отладчика и запускаю приложение прямо из симулятора — Console.app показывает все сообщения. Нет компиляции, нет промежуточных ссылок. Странно.

2. … и еще один более простой результат… Если я запускаю приложение из XCode в сеансе отладки — освобождение не вызывается (журнал не печатается), если я запускаю приложение вручную в симуляторе, а затем подключаю отладчик… все, как и ожидалось.

Ответ №1:

У вас есть NSZombiesEnabled? У нас была такая же проблема, и мы «решили» ее, отключив NSZombies.

«Продукт» -> «Схема» -> «Редактировать схему» -> «Диагностика» -> Снимите флажок «Включить объекты зомби»

Я не уверен, почему dealloc не вызывается, когда включены NSZombies (я почти уверен, что он был вызван до ARC).

Комментарии:

1. Я должен протестировать — но да, у меня установлен NSZombiesEnabled. Это звучит вполне вероятно — и, по крайней мере, дает некоторое разумное объяснение отличному поведению.

2. Я могу подтвердить, что проблема вызвана NSZombiesEnabled. Большое спасибо!

3. Это может происходить повсеместно при использовании NSZombiesEnabled с ARC, а не только с NSOperation . Ключевым моментом при наблюдении странности освобождения с помощью ARC является отключение NSZombiesEnabled (который помечен как «Включенные объекты зомби» в схемах редактирования… > Вкладка Диагностики в Xcode 4.)

4. Причина, по которой dealloc не вызывается, заключается в том, что объект никогда не освобождается. Это предотвращается и вместо этого превращается в «зомби»

5. @borrrden Я думаю, что его можно было бы освободить и просто заменить объектом-зомби по тому же адресу. AFAIK, вот как это работало до arc.

Ответ №2:

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

Я также согласен с тем, что перед ARC в этом случае вызывался dealloc .

После многих тестов выясняется, что освобождение не вызывается при использовании iOS 5.x (устройства или симулятора).

но он вызывается снова (с включенными зомби) в iOS 6.x (устройство или симулятор)

Я не знаю, вызвано ли это изменение ошибкой в ios5, которая была исправлена в ios6, или введенной и откатанной функцией.

Надеюсь, это поможет…

Ответ №3:

Сегодня я столкнулся с такой же проблемой, но моей проблемой был цикл сохранения, сгенерированный блоком.

Если вы используете блоки:

  1. Убедитесь, что SELF не отображается внутри блока.
  2. Если вам нужно использовать SELF внутри блока, используйте слабую ссылку.
  3. Убедитесь, что внутри блока нет макросов, которые могут ссылаться на self (например, NSAssert).