Страницы

Поиск по вопросам

среда, 3 октября 2018 г.

отладка зависающего приложения VS

В Unity зависает редактор. Если сбилдить программу(под вин), то она тоже зависает(no responding). Не могу найти причину: выполняю неопределенное количество раз одно и тоже действие и потом зависание. Поставить breakpoint не могу потому, что не ясно где их ставить. Мне кажется, что зависает где-то в скриптах юнити.
Как можно получить место в котором программа зависает? Можно ли посмотреть какой то журнал где выписаны все действия программы? Я думаю что где-то получается бесконечный цикл, хотя я все циклы проверил...
Спасибо!


Ответ

Есть минимум три решения (если есть другие — дайте знать): два быстрых и одно долгое. Причем долгое связанно именно с Visual Studio (почему у Microsoft не может быть всё просто?)

Наибыстрейшее (но материально затратное)
Нужно пойти в UnityAssetStore и найти ассет (asset) под названием Panic Button. Он находится в разделе Editor Extensions/System. На данный момент этот ассет находится вот здесь
Что он делает? Когда приложение крутится в бесконечном цикле и интерфейс Unity висит, достаточно нажать клавиши Shift + Esc и происходит "обрыв" главного потока, интерфейс отвисает. При этом проигрывание ставится на паузу, а в консоли отображается проблемное место:

Как конкретно она работает? Что происходит внутри? Скорее всего то, что будет описано в пункте №3, только сделанное в виде скрипта, упакованного в dll (чтоб никто не видел код 😆), подключаемую к проекту.

Использовать MonoDevelop
    Шаги следующие:
Пишем скрипт с бесконечным циклом, вешаем на объект и нажимаем Play :-) Идем в MonoDevelop и нажимаем Run → Attach To Process
В появившемся окне выбираем Unity и нажимаем Attach
Нажимаем кнопку Pause в MonoDevelop
Mono уже остановится в проблемном месте и высветится StackTrace
Остается теперь поставить Breakpoint на строку, изменить значение, которое вводит в бесконечный цикл (в данном случае присвоить i значение 20, например) и нажать Continue Execution
Вздохнуть с облегчением.

Использовать Visual Studio
    Шаги:
Пишем скрипт с бесконечным циклом, вешаем на объект и нажимаем Play :-)
Например скрипт такой:
using UnityEngine; public class Quicksand : MonoBehaviour { void OnMouseDown() { while(true) { // "Mind you, you'll keep sinking forever!!", -- My mom } } } Идем в Visual Studio, нажимаем в меню Debug → Attach to Process и выбираем в списке процессов Unity
Заметка (!): Именно Attach to Process, а НЕ Attach To Unity
Далее нажимаем Debug → Break all, чтоб остановить процесс Нужно найти дизассемблированный вид (если он автоматически не появился). В теории на вкладке StackTrace если нажать два раза ЛКМ, то появится окно, в котором можно нажать ссылку view disassembly

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

Из него практически видно бесконечный цикл.
В реальности код может быть сложнее и будет трудно быстро разобрать, что там происходит, но сильно можно не вникать, ибо есть небольшой трюк (см. следующий шаг): F10 - сделать шаг в отладке, не заходя в функцию/метод. Соответственно, теперь пошагово нажимаем F10, пока не перелетим со строки 000000001015A758 jmp 000000001015A743 на строку с инструкцией cmp dword ptr [r11], 0

В итоге во вкладке Autos в Visual Studio должны появится данные значения:
Теперь просто меняем значение "переменной" R11 на ноль (0)
Так как мы стоим на адресе cmp, то при попытки исполнить инструкцию, она попытается прочитать address 0, что, в свою очередь, сгенерирует ошибку. Что мы делаем: Нажимаем F5 (продолжить выполнение программы), а затем во всплывающем окне выбираем Continue
В теории, Unity должна ожить и плюнуть в консоль ошибку, указав, где была загвоздка:
Вздохнуть с облегчением.

P.S. Способ с Visual Studio был позаимствован в блоге Unity. Там же можно прочитать, почему способ работает

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

Отправить комментарий