#c #c 17 #allocator #c pmr
#c #c 17 #распределитель #c pmr
Вопрос:
Я изучаю полиморфное распределение памяти в C 17. Я изменил пример, который использует monotonic_buffer_resource для выделения векторов, чтобы использовать synchronized_pool_resource. Я обнаружил странное поведение. В частности, выделено много памяти, только для двух дополнений в векторе. Я не запускал тесты, но я думаю, что это огромный штраф за производительность
Программа была скомпилирована с использованием O2 g -std=c 17 -O2 -Wall -pedantic
Ниже приведен код
class debug_resource : public std::pmr::memory_resource {
public:
explicit debug_resource(std::string name,
std::pmr::memory_resource* up = std::pmr::get_default_resource())
: _name{ std::move(name) }, _upstream{ up }
{ }
void* do_allocate(size_t bytes, size_t alignment) override {
std::cout << _name << " do_allocate(): " << bytes << 'n';
void* ret = _upstream->allocate(bytes, alignment);
return ret;
}
void do_deallocate(void* ptr, size_t bytes, size_t alignment) override {
std::cout << _name << " do_deallocate(): " << bytes << 'n';
_upstream->deallocate(ptr, bytes, alignment);
}
bool do_is_equal(const std::pmr::memory_resourceamp; other) const noexcept override {
return this == amp;other;
}
private:
std::string _name;
std::pmr::memory_resource* _upstream;
};
int main()
{
debug_resource default_dbg{ "default" };
std::pmr::synchronized_pool_resource pool(amp;default_dbg);
// debug_resource dbg{ "pool", amp;pool };
std::pmr::vector<std::string> strings{ amp;pool };
strings.emplace_back("Hello Short String");
strings.emplace_back("Hello Short String 2");
}
Вывод консоли следующий
по умолчанию do_allocate(): 32
по умолчанию do_allocate(): 528
по умолчанию do_allocate(): 32
по умолчанию do_allocate(): 528
по умолчанию do_allocate(): 1000
по умолчанию do_allocate(): 192
по умолчанию do_allocate(): 968
по умолчанию do_allocate(): 192
по умолчанию do_deallocate(): 528
по умолчанию do_deallocate(): 32
по умолчанию do_deallocate(): 1000
по умолчанию do_deallocate(): 192
по умолчанию do_deallocate(): 968
по умолчанию do_deallocate(): 192
по умолчанию do_deallocate(): 528
по умолчанию do_deallocate(): 32
Комментарии:
1. чтобы увидеть дополнительные выделения для строк, вы должны использовать std::pmr::string в качестве типа для элементов, а не std::string
Ответ №1:
Ответ содержится в описании функции:https://en.cppreference.com/w/cpp/memory/synchronized_pool_resource
Он состоит из коллекции пулов, которые обслуживают запросы для блоков разного размера. Каждый пул управляет коллекцией блоков, которые затем разделяются на блоки одинакового размера.
Вызовы do_allocate отправляются в пул, обслуживающий наименьшие блоки, соответствующие запрошенному размеру.
Исчерпание памяти в пуле приводит к тому, что следующий запрос на выделение для этого пула выделяет дополнительный фрагмент памяти из вышестоящего распределителя для пополнения пула. Полученный размер блока увеличивается геометрически.
Наибольший размер блока и максимальный размер блока могут быть настроены путем передачи структуры std::pmr::pool_options в его конструктор.
Итак, пул на самом деле представляет собой набор блоков памяти. И эта коллекция увеличивается при необходимости. Отсюда множественные выделения.
Чтобы уменьшить количество выделений, вы можете попробовать поиграть с std::pmr::pool_options.