реклама на сайте
подробности

 
 
> Оператор new[] и uCOS-II
aas
сообщение Jun 25 2014, 14:01
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 16
Регистрация: 15-12-11
Из: Краснодар
Пользователь №: 68 865



Доброе время суток!

Имеется контроллер ARM7-TDMI-S (LPC2214), на нем многозадачное приложение C++ с оконной графической оболочкой на основе uCOS-II и uC-GUI. Размер памяти 1 мег. Исключения не используются, STL и шаблоны используются. Компилятор используется GCC.
Вообще я не большой знаток C++ и вообще работы с микрокрнтроллерами, раньше программировал на Java большие веб-порталы, базы данных и т.д. Но мне от предшественника достался уже настроенный проект и среда разработки, т.е. вноси изменения, нажимай кнопочку, и компилируй, прошивай, отлаживай и т.д.

С некоторых пор, когда я сильно увеличил интенсивность использование динамической памяти, около 20-30 обращений в секунду. Программа стала виснуть примерно через 2 - 20 минут работы. На локализацию причины ушло более месяца, и то я не уверен, что локализовал верно.

Начал я с алгоритма распределения памяти, от предшественника досталась папка с исходниками newlib-1.16.0. Оттуда я вытащил исходник malloc и free, интересные алгоритмы, но ничего криминального я там не нашел (спасибо китайцу, их писавшему, очень подробные комментарии оставил, а также больше количество отключаемого диагностического кода!). Как и положено, еще мой предшественник переопределил вызовы, включающие мютекс при обращении к этим функциям. Поигрался я с параметрами компиляции, походил по ним отладчиком, все вроде работает там.
Но потом я заметил, что некорректные адреса иногда возвращает именно вызов new[], а не malloc, причем, new[] сам вызывает malloc, и этот malloc возвращает адреса корректные, а из new[], как правило, тоже вылетают адреса корректные, те же, что malloc вернул. Но иногда вместо них вылетают нулевые указатели, а иногда даже указатели на его собственный, этого самого new[], код (судя по таблице символов), причем, не на точку входа, а куда-то на середину кода. И вот после того, как я по этому указателю что-то пишу, становится все совсем плохо sad.gif.

В общем, заменил я вызов new char[ xxx ] на malloc( xxx ), а delete[] на free(), и все вроде как заработало. Потом я вернул new[] и delete[], но стал запрещать прерывания на время их работы (макросы OS_ENTER_CRITICAL() и OS_EXIT_CRITICAL в uCOS), тоже вроде не падает (по крайней мере, еще не упало, пока я пишу это сообщение...).

Вот я и не понимаю, что такого может быть в new[] и delete[], что они не работаю нормально в много задачной среде? В программе не так уж и много мест, где они вызываются. Даже оконная оболочка ими не пользуется, а обращается напрямую к malloc и free, а с ними то я проблем не нашел. STL еще, наверное, их использует, я так догадываюсь, но он тоже вызывается не так часто. Но все-таки хотелось бы иметь нормальные варианты new и delete, которые корректно конструкторы и деструкторы вызывают, ну и т.д.

Правильно ли я понимаю проблему, и какие есть способы ее решить?

Спасибо за ответы!

Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
AlexandrY
сообщение Jun 25 2014, 15:14
Сообщение #2


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(aas @ Jun 25 2014, 17:01) *
Правильно ли я понимаю проблему, и какие есть способы ее решить?

Спасибо за ответы!


Ну что, видать грабли засели где-то в программе и кто-то портит память в связанных цепочках менеджера управления памятью.
malloc и new скорее всего ни при чем. Просто они пользуются памятью из неудачного места.

А может элементарно стека не хватает по задачу.
Или бывает что стек соседней задачи наезжает на стек задачи которая использует new.
Вообщем начать надо с контроля стеков.

А лучше перейти на Cortex. Там влет с помощью JTAG можно вычислить посторонние записи в память.
Go to the top of the page
 
+Quote Post
aas
сообщение Jun 25 2014, 15:55
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 16
Регистрация: 15-12-11
Из: Краснодар
Пользователь №: 68 865



Цитата(AlexandrY @ Jun 25 2014, 19:14) *
Ну что, видать грабли засели где-то в программе и кто-то портит память в связанных цепочках менеджера управления памятью.
malloc и new скорее всего ни при чем. Просто они пользуются памятью из неудачного места.

А может элементарно стека не хватает по задачу.
Или бывает что стек соседней задачи наезжает на стек задачи которая использует new.
Вообщем начать надо с контроля стеков.

А лучше перейти на Cortex. Там влет с помощью JTAG можно вычислить посторонние записи в память.


Напишу чуть подробнее, что происходит. Я вытащил исходники _malloc_r, _free_r и еще чего-то из этой серии (кажется, _realloc_r и еще что-то, я посмотрел по sym и map файлам, что ко мне линкуется из этих функций, их и вытащил) в файл и прикрепил к сборке. То есть я прикрепил файл, поставил в нем настройки ка для сборки в составе newlib, и открыл макросами сборку только этих функций. Т.е. вся подсистема памяти (в объеме, в котором я ее использую, включая глобальные структуры данных) теперь берется из этого файла, а не из библиотеки. Потом включил я в ней все проверки целостности структур данных, которые еще автор оставил для режима debug, добавил свои кое-какие, в общем весь файл в ассертах, если вдруг что там было бы разрушено, сразу вылетел бы ассерт (у меня он красит низкоуровневым вызовом экран красным и останавливается на точке останова). Поставил также точки останова при возврате нулевого указателя. Более того, адрес последнего выделенного блока памяти пишется в глобальную переменную, чтобы при останове посмотреть, что это было. В общем, по этой причине в корректной работе менеджера памяти у меня сомнений нет.

А вот некорректность new[] я отследил уже двумя способами, во-первых, assert сработал по нулевому указателю, который оно возвращает иногда (причем, malloc, который оно вызвало, вернул указатель нормальный. Во-вторых, assert, который сработал уже во _free_r на то, что указатель не из кучи, да и вообще нечетный (хотя должен делиться на 8). Из кучи адрес или нет, отследить у меня легко: в памяти сначала идут код и статические данные, потом стеки всех задач, потом начинается куча и до конца памяти. Причем, по этому указателю лежит текст, который там и должен лежать, т.е. который я перед этим писал по указателю, который вернул мне new[]. Стеки тоже очень большие, работают от силы на треть размера

P.S. А можно подробнее, какие возможности добавились в Cortex по поиску таких вот неприятных глюков?



Сообщение отредактировал aas - Jun 25 2014, 20:18
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Jun 27 2014, 06:13
Сообщение #4


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(aas @ Jun 25 2014, 18:55) *
А вот некорректность new[] я отследил уже двумя способами, ...

P.S. А можно подробнее, какие возможности добавились в Cortex по поиску таких вот неприятных глюков?


Не там копаете, определенно.... wink.gif

Я работал немало с uC-GUI.
Надеюсь ваш предыдущий разработчик не пытался ее использовать из разных задач одновременно.

Дальше, использование стандартных new и malloc в uCOS это малопонятный выбор.
В uCOS есть свой проверенный действительно многозадачный менеджер памяти.

Разнообразия ошибок у вас должно быть больше.
Припомните не было ли с вашим софтом еще других странностей не объясняемых только проблемой с New.

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

В Cortex-ах на такие действия можно поставить брекпойнт и отследить. В ARM7 такой возможности нет.
Вам надо спускаться на уровень ассемблера и там смотреть состояние и порядок доступа к разным областям памяти. Assert-ы в этой теме как мертвому припарка.

Правда бывают вообще терминальные случаи связанные с особенностями функционирования внешних шин памяти.
Один раз было когда функция пакетного возврата регистров из стека в SDRAM могла исказить содержимое одного из регистров в этом пакете при определенном содержимом соседних регистров.
Хотя отдельное чтение этой ячейки в SDRAM показывало правильное значение.
Вот это был баг! Даже JTAG был бессилен.
Требовалась тончайшая настройка контроллера SDRAM. Проблема целостности сигналов однако. biggrin.gif
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 24th August 2025 - 12:14
Рейтинг@Mail.ru


Страница сгенерированна за 0.01386 секунд с 7
ELECTRONIX ©2004-2016