Зависание платы: Arduino Uno+Ethernet shield

Jluct
Offline
Зарегистрирован: 17.05.2018

Всем доброго времени суток! Пишу проект управления arduino через веб-панель. Столкнулся с проблемой зависания платы. Несколько запросов обрабатываются корректно (~38), а затем плата просто виснет. Проект можно найти по ссылке:

https://bitbucket.org/Jluct/arduino-base-sensors/src/device/

Файл main содержит краткую историю моего дебага и примеры запросов.

В проекте используется парсинг гет запроса. Запрос анализируется и сохраняется в массивах: один с названием параметра, другой со значением. Память выделяю динамически.

Отключив парсинг запросов и заменив всё статичными данными, плата виснуть перестала (по крайней мере во время тестирования зависаний больше не было).

Особую проблему вызывают запросы с двумя параметрами – зависание происходит через меньшее кол-во запросов. Есть подозрение на утечку памяти.

Что бы хоть как-то решить проблему добавил watchdog на 4 секунды. Помогло, но не очень. Это только маскирует проблему, но не решает её.

Очень нужна ваша помощь. С радостью отвечу на любые вопросы.

P.S. проект ещё серьёзно не оформлял (документация, примеры и т.д.), т.к. работаю один и по хорошему его ещё рано показывать)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Одну ошибку я вижу сразу, про неё скажу позже, но поскольку она может быть не единственной, сначала я дам Вам метод исследования памяти.

Я взял Ваш класс Request, ничего в нём не меняя и написал для него простенький тест в несколько строчек в полным контролем памяти. Скачайте архив и запустите тест.

Смотрите, после первого же запуска analyze память у Вас фрагментирована (есть свободные куски между занятыми). После второго - хуже. После третьего формально не хуже, но лишь потому, что новые запросы поместились в свободные куски. Сделайте ещё "длинный" запрос и опять фрагменты добавятся.

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

Теперь про ошибку. В файле Request.cpp в строке 50 Вы запрашиваете память под массив типа String. А в строке 52 Вы запрашиваете память для каждого элемента этого массива. В деструкторе же Вы освобождаете массив (строка 78), а элементы освободить забыли.  Вам надо перед строкой 78 пройти циклом по массиву и освободить память элементов, а уж потом освобождать память самого массива.

Jluct
Offline
Зарегистрирован: 17.05.2018

Большое спасибо за помощь!

Добавил удаление элементов массива params (обновил код в репозитории). Проблему это не решило, но как я понял и не решит, пока не разберусь с памятью. Ваш код запустил в протеусе (avr studio выдаёт ошибку).

Как я понял, вы говорите об участках (и им подобным) отмеченным красным? Честно говоря, понятия не имею как это получается. Можно ли по подробнее об этом? Так же, если можно, расскажите как можно решить данную проблему. Заранее благодарен.

З.Ы. Нашёл вот это. Это мой случай?
https://cdn-learn.adafruit.com/assets/assets/000/010/296/medium800/learn...
 

 

 

 

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Мой код скомпилируйте в ардуино IDE - не будет ошибок, он нормально работает, я проверял. Для студии может потребоваться вставить #include <arduino.h> в файлы быбилиотеки MemoryExplorer, но я в студии его не проверял.

Насчёт "ЗЫ" - оно и есть.

Как исправить.

Берите мой код (потому, что в нём нет ничего лишнего, что может повлиять, там только Request) и запускайте. Смотрите что говорит. Смотрите код. Можете вставлять печать состояния памяти почаще (внутри класса Request).

Коль скоро Вы пользветесь String - очень полезно будет полезть в его исходник, найти там realloc (он там всего один) и поставить после него печать результата запроса памяти и (*this) чтобы понимать какой объект запросил память. И там же в исходнике, найдите free (он там тоже один) и возле него поставьте печать (*this) чтобы понимать какой объект освободил память.

На, а потом, анализируйте всё это.

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

Jluct
Offline
Зарегистрирован: 17.05.2018

Вооружился я протеусом (8.6) и приступил к поиску, кто у меня память крысит. Оказалось класс String не возвращал память. Заменил на char и вроде как заработало)

Ещё раз спасибо за помощь

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Jluct пишет:
Оказалось класс String не возвращал память.

Сам по себе он нормально написан, но таки да - чтобы он прилично вёл себя с памятью, надо хорошо его знать и уметь с ним работать. Если он Вам нравится, то, возможно, лучше освоить правильные приёмы его использования. Хотя, сам я его почти не пользую - просто не имею привычки.