Отладка периодически застрявшего NSOperationQueue - PullRequest
3 голосов
/ 22 ноября 2011

У меня есть iOS-приложение с очень неприятной ошибкой: операция в моем NSOperationQueue по какой-то причине зависает и не завершается, поэтому другие дополнительные операции ставятся в очередь, но все еще не выполняются.Это, в свою очередь, приводит к тому, что приложение не может выполнять важные функции.Я еще не смог идентифицировать какой-либо шаблон, кроме того, что он встречается на одном из моих коллег-устройств каждую неделю или около того.Запуск приложения из Xcode в этот момент не помогает, так как удаление и повторный запуск приложения решают проблему на данный момент.Я попытался подключить отладчик к работающему процессу, и мне кажется, что я вижу данные журнала, но все добавленные точки останова не регистрируются.Я добавил след NSLogs, чтобы попытаться точно определить, где он висит, но это еще не привело к решению.

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

Один мой друг однажды сказал мне, что можно сохранить весь стек памяти приложения в определенный момент в той или иной форме и перезагрузить это точное состояние памяти в процесс на другом устройстве.Кто-нибудь знает, как мне этого добиться?Если это возможно в следующий раз, когда кто-то столкнется с этой ошибкой, я могу сохранить точное состояние памяти и выполнить репликацию, чтобы проверить все мои теории возможных решений.Или есть другой подход к решению этой проблемы?Как временная мера, как вы думаете, имеет ли смысл принудительно вызывать аварийное завершение работы приложения, когда приложение переходит в это состояние, чтобы реальные пользователи были менее смущены?У меня смешанные чувства по этому поводу, но пользователю все равно придется убить приложение из многозадачной док-станции, чтобы снова использовать приложение.Я могу проверить количество очередей операций или создать какой-нибудь код тайм-аута для этого до тех пор, пока я не исправлю эту ошибку.

Ответы [ 5 ]

3 голосов
/ 02 декабря 2011

Звучит как тупик при очень редком состоянии гонки.Вы также упомянули, что maxConcurrentOperationCount равен 2. Это означает, что:

  1. какая-то операция блокирует очередь операции и ждет, пока main освободит некоторую блокировку, а main ждет завершения операции
  2. две операции ждут друг друга, чтобы снять блокировку

1 кажется очень маловероятным, поскольку очередь должна позволять полностью блокировать 2 одновременные операции, если вы не используете некоторые системные функции, которые имеют параллелизмвыдает проблемы и блокирует вашу очередь вместо одного потока.

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

1 голос
/ 30 ноября 2011

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

Добавление: Учитывая ваш ответ в комментариях, мне кажется, что следующим шагом будет использование ведения журнала, когда элемент начинает выполняться в очереди, чтобы вы могли определить, какие это элементы. привести к блокировке очереди. Лучше всего предположить, что это определенный класс предметов или определенные характеристики предметов, если все они принадлежат к определенному классу. В качестве первого шага выполнения каждого элемента достаточно войти в систему, чтобы получить разумную характеристику элемента, а затем, как только вы получите реальное устройство, которое перешло в это состояние, проверьте журналы и посмотрите, какие условия приводят к этой проблеме. Это должно позволить вам надежно воспроизвести проблему на устройстве во время отладки или в симуляторе, а затем зафиксировать ее.

Другими словами - я бы сосредоточил ваше внимание на выявлении проблемных операций в первую очередь, вместо того, чтобы пытаться идентифицировать конкретную строку кода, в которой все останавливается.

1 голос
/ 30 ноября 2011

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

Кроме того, поскольку проблема, по-видимому, связана с NSOperationQueue, возможно, вам следует разделить ее на подклассы, чтобы можно было добавить ведение журнала в более интересные методы. Например, каждый раз, когда добавляется операция, вы должны регистрировать состояние очереди, так как вы подозреваете, что иногда она приостанавливается.

Кроме того, я предложил это и по вашему другому вопросу, вы можете настроить наблюдателя, чтобы получать уведомления, если очередь когда-либо переходит в состояние ожидания.

Удачи.

1 голос
/ 29 ноября 2011

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

Запись вашего журнала на диск каждый раз, когда вы добавляете журнал. Это не самый эффективный способ памяти, но если вы дадите сборку с включенным ведением журнала вашему коллеге, вы можете извлечь журнал с его iPhone, когда что-то пойдет не так. Даже когда приложение все еще работает.

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

Надеюсь, это немного поможет. Я сейчас не о восстановлении состояния памяти приложения, поэтому не могу помочь с этим.

Примечание; Если приложение выдает ошибку, вы могли бы использовать другие инструменты, но если я правильно понял, это не так, не так ли?


Я прочитал вопрос, описывающий ошибку, и попытался бы записать на диск, что делают выполняющиеся в данный момент операции. Кажется, что операции будут зависать время от времени, и там есть ошибка. Если вы можете записывать, какие методы вызываются во время выполнения операции, это покажет вам, какой вызов функции приведет к зависанию приложения, и вы сможете начать поиск там.

0 голосов
/ 24 июля 2017

В моем случае

start

вместо

main

пришлось переопределить.

В случае сомнений проконсультируйтесь с https://developer.apple.com/documentation/foundation/nsoperation#1661262?language=objc на предмет расхождений с вашей реализацией

...