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

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Аллокатор для Cortex-M3, лучшая стратегия выделения памаяти?
brag
сообщение May 28 2012, 15:16
Сообщение #1


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



Как ни крути, а динамическая память всеравно рано или поздно становится необходимой...
Готовые реализации использовать не могу по многим причинам(необходимость иметь несколько арен, thread-safety итп).
Нужен аллокатор, который будет давать минимальную фрагментацию в реальных условиях,минимальный обьем служебной памяти, производительность не особо важна, тк размер арены от силы 32кб.

Реальные условия - одни блоки памяти живут практически forever, другие выделяются/освобождаются подобно стековым переменным - в начале/конце функции соответственно. Блоки разной длины, от 16 до 1024 байт, редко больше. Юзать стек для этого не канает, тк нужно резервировать большие стеки для каждого потока, а это память будет использована на 5-10% в 90% времени.
В основном такое поведение имеет место в GUI и всяких обменах сообщениями, где сами алгоритмы гораздо тяжелее, чем аллокатор.

Пока сделал классическую реализацию best-fit, из служебных полей только размер,бит free/used в начале и в конце блока для облегчения free() и слияния соседних пустых блоков, тобышь заголовок весит 8 байт. Работает все гуд, но хз как оно будет при длительной работе девайса(ну там месяц,2,3).
Курил всякие разные реализации, но там делается упор в основном на производительность, а про фрагментацию редко где упоминается.
По рандом-бенчмаркам best-fit типа рулит, но смущает его тенденция к накоплению кучи маленьких(малоюзабельных) блоков.
First-fit, даже на простых тестах в моих реальных условиях показал гораздо худшую фрагментацию, чем best-fit. next-fit еще хуже.

Если кто-то имел дело с использованием,разработкой аллокаторов - буду благодарен за любую информацию...
Go to the top of the page
 
+Quote Post
Forger
сообщение May 28 2012, 15:37
Сообщение #2


Профессионал
*****

Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831



Цитата(brag @ May 28 2012, 19:16) *
Если кто-то имел дело с использованием,разработкой аллокаторов - буду благодарен за любую информацию...


Я в свое время заморачивался, даже делал дефрагментатор, но это оказалось ненадежным, потому как в таких системах сложно добится детерменирванного времени захвата/высвобождения куска памяти.
По сему я остановился на варианте т.н. pool памяти, но таких пулов не один, а несколько - каждый имеел различный размер кусочков (slice).
Так же был диспетчер всех этих пулов, который сам выбирал при захвате пул с наиболее подходящим размером кусочка.
Т.е. в каждом пуле кусочки равного размера в пределах самого пула, но у каждого пула свой размер кусочков.
Так же этот диспетчер собирал статистику в рабочем режиме, и пре перезапуске прошивки автоматически создавал пулы с размерами кусочков и их числом на основании статистики последнего сеанса работы прошивки (статистика писалась в eeprom).
Пул-память дает четко детерменированное время захвата/освобождения кусочков.
Да и фрагментация как таковая тут полностью отсутствует.
Работало вполне эффективно.
Потом я это переписал на С++ с использованием smart pointer, стало еще удобнее работать - в коде нигде не было new/delete, куски сами освобождались, если на них уже никто не ссылался. Ориентировалось под применение RTOS, хотя можно и без нее.
А обычная куча со всеми ее недостатками, имхо, во встраиваемых приложениях - капризная и ненадежная вещь, уж лучше тогда взять проц с большим объемом памяти, чем кучу использовать. Я стараюсь избегать кучи в embedded проектах.
Ну как-то так sm.gif



--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
Go to the top of the page
 
+Quote Post
brag
сообщение May 28 2012, 16:28
Сообщение #3


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



Спасибо.

Дефрагментатор не годится, тк мы не можем менять физический адрес, mmu в cortex-m3 нету. При наличии mmu, страничной адрессации(виртуальной памяти) фрагментация практически не страшна..

С пулами идея интересная, особенно статистика sm.gif
В принципе можно модифицировать best-fit так, чтобы он не разбивал блоки малого обьема, а оставлял как есть. По идее, тогда туда будут падать те же запросы. Хотя такое ограничение уже есть - свободный блок дожнен быть такой, чтобы туда влезли заголовки и хотябы одно слово памяти (сейчас это 12байт), можно просто этот предел увеличить.
Благо, риалтайм не нужно, GUI,сеть,.. вещи довольно не риалтайм да и ОС у меня тоже не рт. Вообще рт вещи привык делать без OС на отдельных камнях, но эт уже не та тема..

Цитата
А обычная куча со всеми ее недостатками, имхо, во встраиваемых приложениях - капризная и ненадежная вещь, уж лучше тогда взять проц с большим объемом памяти, чем кучу использовать. Я стараюсь избегать кучи в embedded проектах.

Ну их больше как-бы нету sm.gif 64кб практически потолок, если забить все статикой и стеками, то не хватит их, при чем процентов 80 будет реально пустовать. Тут только внешняя память решает, но это дорого. Был бы мегабайт - стека вполне хватило бы..
Согласен, кучи - зло, но динамическая память нужна sad.gif

За smart pointer спасибо. подобную технику reference counter уже использую, но там aquire и forget кишит, ну да, delete нету sm.gif
А про него можно по подробнее, как удалось избавится от слежения(new,delete,aquire,forget) за обьектом?

апд.

Сама куча будет использоватся исключительно для хранения в ней обьектов C++, тоесть функций malloc(),free() нету как таковых. не помешает выделение блоков фиксированной длины с каким-то шагом(возможно просто степень двойки) - по идее тоже должно уменьшить фрагментацию + ограничение на разбиение малых блоков либо вообще запрет использования блоков неподходящей длины(тоже с каким-то порогом) - в итоге появятся редкоиспользуемые блоки небольшой длины, но другие блоки будут использоватся активно. по идее в таком случаи фрагментация дорастет до какого-то предела и дальше перестанет расти
Go to the top of the page
 
+Quote Post
Forger
сообщение May 28 2012, 17:01
Сообщение #4


Профессионал
*****

Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831



Цитата(brag @ May 28 2012, 20:28) *
А про него можно по подробнее, как удалось избавится от слежения(new,delete,aquire,forget) за обьектом?


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

Т.е. это - не просто смарт поинтер, а нечто посложнее, к тому же у меня для этой цели использовался вроде как шаблон, а не простое наследование от некого класса.
Я щас, увы, уже не найду тот код sad.gif
Только помню, что там такое делал и даже делал подобное не только там, а еще где-то. Видать, поэтому и помню sm.gif

Цитата
...другие блоки будут использоватся активно. по идее в таком случаи фрагментация дорастет до какого-то предела и дальше перестанет расти

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


--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
Go to the top of the page
 
+Quote Post
brag
сообщение May 28 2012, 17:08
Сообщение #5


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



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

smart pointer пытаюсь что-то такое слепить, вроде получается sm.gif обьеденить reference counter с smart pointer-ом + всякая хитрая перегрузка. не охота сильно наворачивать wink.gif
Go to the top of the page
 
+Quote Post
scifi
сообщение May 28 2012, 18:24
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(brag @ May 28 2012, 19:16) *
Реальные условия - одни блоки памяти живут практически forever, другие выделяются/освобождаются подобно стековым переменным - в начале/конце функции соответственно.

Ну так и нужно сделать два аллокатора: один - простейшая куча (для долгоживущих блоков), а другой - чистый стек. В процедуру выделения памяти передавать параметр для выбора правильного аллокатора.
Go to the top of the page
 
+Quote Post
brag
сообщение May 28 2012, 18:46
Сообщение #7


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



Чистый стек не идет. Потоков много, вызывающих одни и те же функции. в этих функциях выделяются освобождаются блоки подобно автоматическим переменным. На стеке их создавать нельзя - нужны большие стеки для каждого потока. В общем стеке тоже не идет - потоки работают асинхронно.
Куча надо по-любому, но какая-то хитрая, шоб и кучу мелких фрагментов не плодила и памяти много не жрала
Go to the top of the page
 
+Quote Post
jcxz
сообщение May 29 2012, 02:24
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(brag @ May 29 2012, 00:46) *
Чистый стек не идет. Потоков много, вызывающих одни и те же функции. в этих функциях выделяются освобождаются блоки подобно автоматическим переменным. На стеке их создавать нельзя - нужны большие стеки для каждого потока. В общем стеке тоже не идет - потоки работают асинхронно.
Куча надо по-любому, но какая-то хитрая, шоб и кучу мелких фрагментов не плодила и памяти много не жрала

Раз у вас не хватает памяти чтобы распределить её в виде static или на стеке для всех потоков, значит возможна ситуация (и даже с большей вероятностью), когда много потоков запросит больше памяти чем есть. С наличием служебных полей управления блоками в heap и фрагментации это даже более вероятно, чем при static размещении.
Что ваша система должна делать при этом? Выдать отказ потоку (но значит алгоритм всех потоков должен рассчитывать, что может быть получен отказ в памяти)? Или приостановить выполнение потока (но может случиться dead-lock)?

Я полностью согласен с Forger - делаю так же - стараюсь обходиться static. Если невозможно - использую динамическое выделение блоков фиксированной длины. Даже в довольно сложных проектах с многими потоками нигде не использую стандартный heap.
Также помогает знание алгоритма работы потоков: где-то можно использовать union если нет одновременного использования памяти, где-то можно ставить семафоры на функции использующие большие блоки статической памяти и т.п.
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение May 29 2012, 06:31
Сообщение #9


Ally
******

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



Цитата(Forger @ May 28 2012, 18:37) *
По сему я остановился на варианте т.н. pool памяти, но таких пулов не один, а несколько - каждый имеел различный размер кусочков (slice).
Так же был диспетчер всех этих пулов, который сам выбирал при захвате пул с наиболее подходящим размером кусочка.

Работало вполне эффективно.


Как вы, интересно, определили его эффективность.
Как то не приходилось видеть движков которые бы сами эффективно могли бы создавать правильные распределения пулов фиксированного размера.
Да и сомнительно насчет сбора статистики. Сама такая статистика требует heap-а неопределенного размера.
А если все таки статистика была компактной, то какой смысл был ее собирать, анализ исходников ответил бы на все вопросы.

Go to the top of the page
 
+Quote Post
Forger
сообщение May 29 2012, 08:08
Сообщение #10


Профессионал
*****

Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831



Цитата(AlexandrY @ May 29 2012, 10:31) *
Как вы, интересно, определили его эффективность.

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

Вообще, в моих реальных проектах это нафик не было нужно: я просто закладываю больше памяти.
Так выходит быстрее, проще и надежнее sm.gif А цена ОЗУ? Так в моих проектах она вообще некритична - мелкосерийные изделия, епта.

Цитата
Как то не приходилось видеть движков которые бы сами эффективно могли бы создавать правильные распределения пулов фиксированного размера.
Да и сомнительно насчет сбора статистики. Сама такая статистика требует heap-а неопределенного размера.

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

Цитата
А если все таки статистика была компактной, то какой смысл был ее собирать, анализ исходников ответил бы на все вопросы.

Мне кажется, что анализ исходников не даст полной картины в многопоточном приложении, в динамике.
Но анализ кода даст точную картину при статических объектах, да и это сам компилятор/линкер дает sm.gif


--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
Go to the top of the page
 
+Quote Post
neiver
сообщение May 29 2012, 11:50
Сообщение #11


Местный
***

Группа: Участник
Сообщений: 214
Регистрация: 22-03-10
Из: Саратов
Пользователь №: 56 123



Цитата(brag @ May 28 2012, 22:46) *
Чистый стек не идет. Потоков много, вызывающих одни и те же функции. в этих функциях выделяются освобождаются блоки подобно автоматическим переменным.

При таком использовании может подойти аллокатор, который выделяет память последовательно из пула фиксированного размера и не освобождает её. Освобождается весь пул при выходе из функции. А пулы памяти можно выделять, например, с помощью bitmap allocator.
Go to the top of the page
 
+Quote Post
brag
сообщение May 29 2012, 13:15
Сообщение #12


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



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

Таки ваша правда... Но работать с динамикой гораздо удобнее, чем передавать в каждую функцию указатели на буфферы, да еще и следить везде за размером.
Потом это не просто буфферы, а там классы, программа будет пестреть reinterpret_cast, что вообще не красиво и склонно к образованию разных багов.
В принципе серьезно задумываюсь над стеком, разделить тяжелые потоки и легкие отдельно. надо написать хороший анализатор стека, чтобы indirect-высовы понимал(виртуальные классы), рекурсия - фиг с ней, редко где применяется. Сейчас я сделал анализатор стека, но он понимает все, кроме индирект call...

кому надо - могу дать.

Цитата
При таком использовании может подойти аллокатор, который выделяет память последовательно из пула фиксированного размера и не освобождает её. Освобождается весь пул при выходе из функции. А пулы памяти можно выделять, например, с помощью bitmap allocator.

Да, вариант тоже неплох, обдумаем, спасибо
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение May 29 2012, 13:42
Сообщение #13


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Цитата(Forger @ May 28 2012, 18:37) *
А обычная куча со всеми ее недостатками, имхо, во встраиваемых приложениях - капризная и ненадежная вещь, уж лучше тогда взять проц с большим объемом памяти, чем кучу использовать. Я стараюсь избегать кучи в embedded проектах.
Ну как-то так sm.gif

Что значит ненадёжная? Чем она более ненадёжная, чем любой другой элемент программирования.
Я делал. Только дефрагментацию делал в защищённой секции. Причём не всю дефрагментацию, а лишь её завершающую стадию. Всё работало устойчиво.
Универсально задача решается сложно. А вот под реальную задачу можно поэкспериментировать.

Понятно, что раз такой вопрос становится, то принципиально может возникнуть ситуация, когда память не может быть выделена. Значит алгоритм работы должен предусматривать такой вариант. (У меня, например приостанавливалась подкачка, пока не разгрузится память)
А задачи, где динамическое выделение памяти целесообразно есть. Сейчас я одну такую решаю. На первом этапе буду работать с статическим распределением. Потом прикручу динамическое.
Go to the top of the page
 
+Quote Post
jcxz
сообщение May 29 2012, 15:19
Сообщение #14


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(brag @ May 29 2012, 19:15) *
Таки ваша правда... Но работать с динамикой гораздо удобнее, чем передавать в каждую функцию указатели на буфферы, да еще и следить везде за размером.
Потом это не просто буфферы, а там классы, программа будет пестреть reinterpret_cast, что вообще не красиво и склонно к образованию разных багов.

А зачем? Или вы про вызов конструкторов классов для буфера?
Но что мешает явно его вызвать:
char buf[N];
new (buf) ClassName(...);
ClassName *p = (ClassName *)buf;
...

Go to the top of the page
 
+Quote Post
ReAl
сообщение May 29 2012, 18:13
Сообщение #15


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(jcxz @ May 29 2012, 18:19) *
char buf[N];
new (buf) ClassName(...);
ClassName *p = (ClassName *)buf;

Ну так этот «С-шный каст» ничем не лучше reinterpret_cast<>

Впрочем, тут без кастов можно и нужно. Раз уж placement new используется, его надо и использовать правильно:
Код
char buf[ sizeof(ClassName) ];

ClassName *p = new (buf) ClassName(...);

p.s. ещё тут


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 18th July 2025 - 08:03
Рейтинг@Mail.ru


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