2013-04-10 4 views
9

Сегодня у меня была довольно интересная авария exc_bad_access. После многократного копания я придумал следующую информацию (работает в симуляторе):Как NSLogs может привести к сбою кода?

Если я только что запустил код, приложение случайно разбилось бы в случайной точке при загрузке данных в мой управляемый объект. Из того, что я мог сказать, он всегда терпел крах, когда я загружал данные в управляемый объект, а не в разделы, которые преобразовывались из моего JSON-dict в данные к фактически используемому объекту (из строк и NSNulls в ints/float и nils)

Случайные сбои, конечно, злые, поэтому я попытался пройти процесс в отладчике, но это оказалось нецелесообразным - я обрабатывал много объектов, поэтому каждый шаг через них просто не работал. Поэтому я решил добавить некоторые NSLogs для отслеживания процесса и попытаться найти шаблон таким образом.

Мгновенно разрешили сбой.

Только один NSLog в любом месте этого процесса предотвратил сбой.

В конечном итоге я отслеживал путь к трассировке стека и обнаружил актуальную проблему: я обращался к управляемому объекту в потоковой среде, но НЕ из-за связанного с ним метода выполненияBlockAndWait:. В этот момент крушение было невероятно очевидным для меня - я в шоке, у меня больше не было проблем. Я готов поспорить, что между наличием «небольшого» набора тестовых данных из 2-3 объектов и наличием отладочного кода там с NSLogs ошибка была довольно эффективно замаскирована ранее ... но вопрос остается:

Почему делает NSLog препятствовать тому, чтобы приложение разбилось? Как на самом деле фрагмент кода без побочных эффектов изменил выполнение остальной части приложения? Это не имеет никакого смысла!

+0

Используете ли вы где-нибудь функциюSelector: метод и селектор, который возвращает не тип id в качестве параметра для него? Несколько раз NSLog может предотвратить ошибки, связанные с этими ошибками.В этом случае нужно использовать NSInvocation – BergP

ответ

12

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

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

+0

Не знал этого. Хороший, +1. Просто ничего себе. – 2013-04-10 19:05:11

+0

Никогда даже не думал об этой возможности, но я думаю, что это может привести к огромным изменениям в том, как работает мой код. Cool – RonLugge

+1

@RonLugge Вся наша команда была ошеломлена, когда мы впервые сделали это открытие: мы получили сообщения о частых случайных авариях с одного из наших установленных сайтов, попросили их перевести уровни журналов с «error» на «debug », и пришлите нам журналы. Когда они вернулись к нам с ответом, что, как только они подняли уровни журнала, они больше не могут воспроизвести крах, мы сначала не верили им. Но как только мы отключили ведение журнала (это всегда был «включен» в развитие), мы сами воспроизвели катастрофу :) – dasblinkenlight

3

Почему NSLog предотвращает сбой приложения? Как мог бы код без побочных эффектов изменить выполнение остальной части приложения? Это не имеет никакого смысла!

Действительно, это имеет смысл. В самом деле.

Сила, предназначенная для печати чего-либо на вашей консоли, занимает немного времени, а между обработкой на somethread завершается и может произойти сбой (возможно, из-за отсутствия доступа).

Возможно, это связано с асинхронным вызовом. Ваш следующий процесс начинается до окончания предыдущего. И вашему следующему процессу нужны данные из предыдущего процесса. NSLog потребляет некоторое время.

+0

Хотя я думал об этом, в этом контексте мне не было смысла - хотя я могу быть в многопоточной среде, только одна «копия» этого кода будет работать при любом заданном (так что у меня будет «основной поток» и «поток данных»). Независимо от того, что управляемые объекты небезопасны, не следует выполнять NSLog ... Я думал. – RonLugge

+0

Я встречаюсь с ними довольно регулярно :( –

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