Разрешение размещения объектов в куче внутри недолговечной области для обеспечения свободы фрагментации памяти

Мы используем C ++ во встроенной системной среде и в основном не хотим никакого динамического распределения памяти (см., Например, Ресурсы для управления памятью во встроенном приложении по тем же причинам, по которым мы этого не делаем). Тем не менее, мы не хотим обойтись без некоторых хороших функций на основе C ++, таких как контейнеры STL и std :: string. Для первого мы зарезервируем определенный размер при инициализации и не позволим контейнеру вырасти за пределы своей емкости. Что касается последних (std :: string), я немного скептически относился к тому, как их использовать «безопасно», поскольку они иногда выделяют память в куче.

Тем не менее, я обнаружил обстоятельства, при которых использование std :: string (и, как правило, других объектов, выделяющих кучу) вполне допустимо: я бы выделил сам объект в стеке (в определенной области, ограниченной {}, поскольку я говорит с C ++) и позволяет им выделять кучу при условии, что они фактически освобождают всю свою зарезервированную память, когда они выходят за пределы области видимости.

Я понимаю, что этот метод определенно не гарантирует свободу фрагментации памяти, но я чувствую, что если рассматриваемая область действия недолговечна, это на самом деле приводит к непрерывной свободной памяти после ее окончания.

У меня также были сомнения, что может возникнуть проблема, когда несколько задач используют одну и ту же кучу, но все же свободная память должна быть непрерывной в конце при условии, что все доступные области недолговечны (например, не блокируются). В качестве альтернативы для меня было бы приемлемо, что только одной задаче разрешено выделять память в куче, а другим - нет, если это действительно имеет значение.

Допустимо ли предложенное мной использование объектов, выделяющих кучу? Есть ли у кого-нибудь другая стратегия (частично) для включения динамического распределения памяти без риска фрагментации памяти?


person Roland Sarrazin    schedule 06.05.2013    source источник
comment
Трудно ответить, не зная, какую систему вы используете. Я, например, работаю над встроенным Linux, и у меня никогда не было проблем с фрагментацией памяти, хотя память небольшая (64 МБ) и устройство постоянно работает.   -  person syam    schedule 06.05.2013
comment
@syam: 64МБ == маленький? Я бы посчитал 64 * K * B большим в некоторых своих проектах :)   -  person Martin Thompson    schedule 10.05.2013


Ответы (2)


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

Кроме того, для всех небольших (‹64 байтов) выделений, которые C ++ любит делать при помощи пар и управляющих структур, важна схема распределения модулей - не только для контроля фрагментации, но и для производительности. Распределитель модулей предварительно выделяет количество единиц памяти одинакового размера (скажем, 64 байта) и помещает их в свободный стек. По мере выделения памяти вы извлекаете их из свободного стека и возвращаете. Поскольку все размеры идентичны, у вас есть только внутренняя фрагментация до размера блока. Поскольку вам не нужно присоединять память, когда это сделано, выделение и освобождение занимает O (1) раз.

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

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

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

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

person Michael Dorgan    schedule 06.05.2013
comment
Это то, что иногда называют распределителем пула? Мне было интересно, может ли это помочь в подобной проблеме. - person JBL; 06.05.2013
comment
Я забыл уточнить, что мы на самом деле предпочитаем использовать пулы памяти для долгоживущих объектов. Я определенно просил недолговечные предметы. Я благодарю вас за ответ, поскольку он дает мне много пищи для размышлений, но все же я упускаю подтверждение того, что мой подход, основанный на области видимости, действителен. - person Roland Sarrazin; 06.05.2013
comment
Память на основе области работает до тех пор, пока вы не смешиваете долгосрочное распределение в той же куче / пуле, что и ваше выделение в области видимости. Это лучшее подтверждение, которое я могу вам дать. - person Michael Dorgan; 06.05.2013
comment
Я не думаю, что люди понимают alloca C ++. Память не разбрасывается, она автоматически освобождается при возврате метода. Часто C ++ нуждается в динамически выделяемых объектах, даже когда используется как временный. Чтобы использовать alloca, вам понадобится умный указатель / RAII и placement new. alloca не соответствует общему требованию. Большинство распределителей - это распределители, расположенные снизу, и, естественно, выполняют объединение. Если у вас есть способ объединиться, вы получите наименьшую фрагментацию. - person artless noise; 07.05.2013
comment
В своем ответе у вас есть: Во-первых, пулы памяти - ваш друг - как говорится в статье - можете ли вы дать ссылку на статью, на которую вы ссылаетесь? - person Michael Burr; 10.05.2013
comment
Из исходной ссылки OP в фразе «Ресурсы для управления памятью во встроенном приложении» - одна обратно в другую статью SO. - person Michael Dorgan; 11.05.2013

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

Изменить: некоторая информация о alloca из документации библиотеки GNU C < / а>.

person Marc Claesen    schedule 06.05.2013