Суть проблемы.
Ваше запущенное приложение в какой то момент начинает активно грузить CPU, вас зовёт тестер и просит починить это!
Какие обычные действия программистов в таком случае?
- Просят локализовать, если получается, то решить проблему вопрос времени.
- Начинается добавление логов, счетчиков проходов и тому подобного. Все отдается тестеру или заказчику с требованием воспроизвести и вернуть лог на анализ. Хорошо если воспроизвести удастся и все станет ясно.
- Предположить время, когда "все работало" и по изменениями в системе контроля версий искать возможные причины.
Как проще поступить вэтом случае?
Загрузка CPU означает, что какой то поток(и) обработки данных проснулся\запустился, и стал активно выполнять свою работу или иногда просто зациклился. Узнав стек выполнения в момент нагрузки, можно с высокой долей вероятности понять причину такого поведения.
Как же его можно узнать, ведь мы не находимся под отладчиком? Лично я пользуюсь утилитой Process Explorer дающая возможность увидеть список потоков и их стек. Программа установки не требует.
Для демонстрации я запустил свое приложение с именем процесса "Qocr.Application.Wpf.exe", в которое добавил фейковый код бесконечного цикла. Теперь давайте найдём причину загрузки ядра без отладчика. Для этого я иду в ствойства процесса, далее:
- Переходим на вкладку Threads и видим, что имеется 1 поток, который грузит на 16% CPU.
- Выделяем этот поток и жмем Stack, открылось окно "Stack for thread ID".
- В окне видим, что наш поток был создан тут Qocr.Application.Wpf.exe!<>c.
b__36_1+0x3a и в данный момент вызывает GetDirectories из метода InitLanguages().
Продемонстрирую действия выше на изображении со стрелками:
Открыв исходный код программы и перейдя к методу InitLanguages можно увидеть мой фейковый код. Зная эту информацию, а именно место отстановки, можно уже принимать меры.
Код стека (из примера выше) вызывающий бесконечный цикл (Можно проверить):
private void InitLanguages() { new Thread( () => { while (true) { var dir = Directory.GetDirectories(@"C:\"); } ; }).Start(); }
Ложка дегтя в бочке с медом.
Два момента, которые стоит знать, если решите воспользоваться способом выше:
- Потоки созданные CLR (созданные в коде .NET приложения) после останова не продолжают выполнение. В результате чего поток останавливается и остается висеть до перезапуска программы.
- Если стек исполнения не содержит полезной информации, то стоит проделать остановку и просмотр стека несколько раз. Вероятность наткнуться на место зацикливания очень велика.
Все работает Спасибо вам !!!!
ОтветитьУдалитьСпасибо, Сергей, нашел вечный цикл за минуту!
ОтветитьУдалитьОчень рад что кому то пригодилось
ОтветитьУдалить