【问题标题】:boost beast async_write increases memory footprint dramaticallyboost beast async_write 显着增加了内存占用
【发布时间】:2019-07-10 16:29:02
【问题描述】:

我目前正在试验 boost beast 库,现在对它的内存占用感到非常惊讶。我发现通过使用三种不同的响应类型(字符串、文件、动态),程序大小会增长到 6Mb。

为了更接近原因,我从库中提取了小型服务器示例并将其简化为以下步骤:

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

删除所有 cmets 后,最终大小变为:

   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")));
}

提前致谢

【问题讨论】:

  • 我没有使用过野兽,但如果目标不接受写入,异步 IO 会将写入放入内存。那么,您的听众是在阅读它的输入还是只是坐在那里?而且,如果网络遇到了像 WiFi 这样的慢速网络,则很有可能通过将整个文件写入目标来堆积数兆字节的 RAM。您将希望限制一次缓冲的数量和/或使用诸如 sendfile 之类的 OS API。
  • 哦,你说的是程序的编译大小而不是运行时大小。它可能是构建大量内联和重复代码的模板。还有异常和 RTTI 信息。你可以看看在发布模式下构建是否有帮助。
  • @Zan Lynx 当然是模板的东西。我正在使用 -o2 标志进行构建,但没有调试信息。
  • 您是否有理由必须关心可执行文件的大小?还是因为担心 6MB 的可执行文件比 2MB 的可执行文件慢?
  • 你不能连续调用async_write两次,你必须等待第一个完成才能调用第二个。

标签: c++11 templates gcc boost boost-beast


【解决方案1】:

如果您实际上没有泄漏内存,那么就没有错。系统分配的任何内存都将重新用于您的程序或最终归还。由于虚拟内存系统,很难测量程序的真实内存使用情况,尤其是在 Linux 下。除非您看到实际的泄漏或真正的问题,否则我会忽略这些内存报告并继续实现您的业务逻辑。 Beast 本身没有内存泄漏(在 valgrind、asan 和 ubsan 下的 Travis 和 Appveyor 上进行了广泛的每次提交测试)。

【讨论】:

    【解决方案2】:

    尝试使用 malloc_trim(0) ,例如:在 http_connection 的析构函数中。

    来自man: malloc_trim - 从堆顶释放空闲内存。

    malloc_trim() 函数尝试释放堆顶部的空闲内存(通过使用合适的参数调用 sbrk(2))。

    pad 参数指定在堆顶部保留未修剪的可用空间量。

    如果此参数为 0,则仅在堆顶部保持最小内存量(即一页或更少)。非零参数可用于在堆顶部维护一些尾随空间,以允许将来进行分配而不必扩展堆 sbrk(2)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-16
      • 2019-10-13
      • 1970-01-01
      • 2011-05-03
      相关资源
      最近更新 更多