boost beast async_write значительно увеличивает объем памяти
В настоящее время я экспериментирую с библиотекой boost beast и теперь очень удивлен ее объемом памяти. Я обнаружил, что используя три разных типа ответа (строковый, файловый, динамический), размер программы увеличивается до 6 МБ.
Чтобы приблизиться к делу, я взял небольшой пример сервера из библиотеки и сократил его до следующих шагов:
class http_connection : public std::enable_shared_from_this<http_connection>
{
public:
http_connection(tcp::socket socket) : socket_(std::move(socket)) { }
void start() {
read_request();
}
private:
tcp::socket socket_;
beast::flat_buffer buffer_{8192};
http::request<http::dynamic_body> request_;
void read_request() {
auto self = shared_from_this();
http::async_read(
socket_, buffer_, request_,
[self](beast::error_code ec,
std::size_t bytes_transferred)
{
self->write_response(std::make_shared<http::response<http::dynamic_body>>());
self->write_response(std::make_shared<http::response<http::file_body>>());
self->write_response(std::make_shared<http::response<http::string_body>>(), true);
});
}
template <class T>
void write_response(std::shared_ptr<T> response, bool dostop=false) {
auto self = shared_from_this();
http::async_write(
socket_,
*response,
[self,response,dostop](beast::error_code ec, std::size_t)
{
if (dostop)
self->socket_.shutdown(tcp::socket::shutdown_send, ec);
});
}
};
когда я закомментирую три строки self->write_response, скомпилирую программу и выполню команду size для результата, я получаю:
text data bss dec hex filename
343474 1680 7408 352562 56132 small
Когда я удаляю комментарий первой записи, то получаю:
864740 1714 7408 873862 d5586 small
text data bss dec hex filename
После удаления всех комментариев конечный размер становится:
text data bss dec hex filename
1333510 1730 7408 1342648 147cb8 small
4,8M Feb 16 22:13 small*
Вопрос сейчас:
Я делаю что-то неправильно?
Есть ли способ уменьшить размер?
ОБНОВИТЬ
настоящий process_request выглядит так:
void process_request() {
auto it = router.find(request.method(), request.target());
if (it != router.end()) {
auto response = it->getHandler()(doc_root_, request);
if (boost::apply_visitor(dsa::type::handler(), response) == TypeCode::dynamic_r) {
auto r = boost::get<std::shared_ptr<dynamic_response>>(response);
send(r);
return;
}
if (boost::apply_visitor(dsa::type::handler(), response) == TypeCode::file_r) {
auto r = boost::get<std::shared_ptr<file_response>>(response);
send(r);
return;
}
if (boost::apply_visitor(dsa::type::handler(), response) == TypeCode::string_r) {
auto r = boost::get<std::shared_ptr<string_response>>(response);
send(r);
return;
}
}
send(boost::get<std::shared_ptr<string_response>>(send_bad_response(
http::status::bad_request,
"Invalid request-method '" + std::string(req.method_string()) + "'\r\n")));
}
заранее спасибо
1 ответ
Если вы на самом деле не теряете память, то в этом нет ничего плохого. Независимо от того, какая память выделена системой, она будет либо повторно использована для вашей программы, либо в конечном итоге возвращена. Из-за системы виртуальной памяти очень трудно измерить истинное использование памяти программой, особенно в Linux. Если вы не увидите фактическую утечку или реальную проблему, я проигнорирую эти отчеты о памяти и просто продолжу реализацию вашей бизнес-логики. Сам зверь не содержит утечек памяти (тщательно протестирован на коммитах на Travis и Appveyor в valgrind, asan и ubsan).
Попробуйте использовать malloc_trim(0)
, например: в деструкторе http_connection
.
от man
:
malloc_trim - освободить свободную память сверху кучи.
Функция malloc_trim() пытается освободить свободную память в верхней части кучи (вызывая sbrk(2) с подходящим аргументом).
Аргумент pad указывает количество свободного пространства, которое следует оставить необрезанным в верхней части кучи.
Если этот аргумент равен 0, то в верхней части кучи поддерживается только минимальный объем памяти (то есть одна страница или меньше). Ненулевой аргумент может использоваться для сохранения некоторого конечного пространства в верхней части кучи, чтобы позволить будущие выделения памяти без необходимости расширения кучи с помощью sbrk(2).