Boost::asio 和 boost::bind:Functor 内存永远不会被释放

2024-03-29

我的代码正在分配内存并且从不释放它,即使它应该(至少在我看来)。

标题看起来像这样:

typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> sslSocket_t;

class Object {
    boost::asio::io_service ioService_;
    boost::asio::ip::tcp::acceptor acceptor_;
    boost::asio::ssl::context context_;

    void functionOne();
    void functionTwo(shared_ptr<sslSocket_t>& sslSocket, const boost::system::error_code& error)
}

我的来源是这样的:

void Object::functionOne() {
    for (int i = 0; i < 10; i++) {
        shared_ptr<sslSocket_t> sslSocket(new sslSocket_t(ioService_, context_));
        acceptor_.async_accept(sslSocket->lowest_layer(),
                       boost::bind(&Object::functionTwo, this, sslSocket, boost::asio::placeholders::error));
    }
    acceptor_.cancel();

    boost::asio::io_service::work work(ioService_);
    ioService_.run();
}

void functionTwo(shared_ptr<sslSocket_t>& sslSocket, const boost::system::error_code& err) {
    // Do nothing
}

所以当我打电话时对象.functionOne(),内存被分配给对象.ioService_对象,以便能够调用绑定的异步方法。然后在循环之后,接受器上所有挂起的异步操作都将被取消。一旦出现以下情况,就会调用适当的处理程序Object.ioService_.run()被称为(我一直在测试)。但由于某种原因,分配的内存没有被释放。那么有人可以解释一下为什么内存没有被释放并给我一个提示如何释放它吗?

顺便说一句:我正在 Debian 上工作并正在研究/proc/自我/状态 -> VmRSS查看已使用的内存。

@维尼·法尔科

#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/bind.hpp>

#include <iostream>
#include <memory>

typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> sslSocket_t;

using namespace std;

struct T  {

    boost::asio::io_service ioService_;
    boost::asio::ip::tcp::acceptor acceptor_;
    boost::asio::ssl::context context_;

    void functionOne() {
        for (int i = 0; i < 10; i++) {
            shared_ptr<sslSocket_t> sslSocket(new sslSocket_t(ioService_, context_));
            acceptor_.async_accept(sslSocket->lowest_layer(),
                               boost::bind(&T::functionTwo, this, sslSocket, boost::asio::placeholders::error));
        }
        acceptor_.cancel();

        boost::asio::io_service::work work(ioService_);
        ioService_.run();
    }

    void functionTwo(shared_ptr<sslSocket_t>& sslSocket, const boost::system::error_code& err) {
        // Do nothing
    }

    T() : acceptor_(ioService_,
                    boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 443)),
          context_(boost::asio::ssl::context::sslv23_server)  {

    }

    ~T()  {

    }
};

int main()  {

    try  {
        T t;

        t.functionOne();
    } catch (std::exception& e) {
        cout << "Exception: " << e.what() << endl;
  }
}

我的问题不是,是否以及为什么析构函数T被称为,这按预期工作。但有关已用内存的行为很奇怪。 因此,如果增加 for 循环中的限制,您将观察到程序保留了大量内存,即使在调用所有异步处理程序后应该释放它。但是SSL套接字对象没有被释放,这就是我的问题:为什么内存(特别是为 sslSocket 分配的内存)绑定到函子功能二,即使在异步方法之后也不会释放功能二已被调用并且没有引用SSL套接字离开了?

我解释我的担忧的最后方法(4 月 28 日编辑)

好吧,我做了一个可运行的例子,这表明了我的担忧:我的问题在一个例子中 http://melpon.org/wandbox/permlink/S56tYueJySIHdsWO

Output:

Before leaking call:     6984 kB
Asynchronous calls of functionTwo: 10000
Memory while ioService is still running:   460244 kB
Memory after ioService is stopped:   460244 kB

更疯狂的是,在我自己的本地实现中,我得到以下输出:

Memory leaking call:     8352 kB
Asynchronous calls of functionTwo: 10000
Memory while ioService is still running:   471932 kB
Memory after ioService is stopped:     8436 kB

因此可以清楚地看到:即使调用了所有异步操作,内存也没有被释放。

总结和理解(?)行为(最后编辑)

正如你们中的一些人可能误解的那样,我并不认为我的代码中存在某种泄漏。我在代码示例中命名了该结构Leak,这可能会让您感到困惑,但我的问题不是我的示例中是否以及在何处发生内存泄漏。这是关于内存分配与io服务目的。首先我认为,所声称的内存正在无限增加。我采用了最后一种方法来理解这种行为,并得出结论:内存管理没有问题。操作系统不会回收内存,但程序的内存分配会收敛到一个限制,这对我来说没问题。所以这个问题不适合我。

示例:聚合内存消耗 http://melpon.org/wandbox/permlink/i5k59o38K8azDX2o

最让我不安的是我的本地实现表现出略有不同的行为。在那里,内存被操作系统回收,当io服务对象已完成其工作并重置,这满足了我的期望。

总结一下所有的观察结果:

分配的内存由 C++ 运行时和操作系统管理。直接观察分配过程是相当困难的(如果不是不可能的话?),因为它经过优化以减少对新内存页面的请求量,这意味着分配和freed操作系统可能不会立即重新分配内存。

为了向我指出这种行为的关键点,我想描述我的程序的用法:我正在开发一个服务器应用程序,这意味着该程序应该运行无限的时间。如果程序在某个时间声明了大量的峰值内存,那完全没问题,但它需要在运行时的某个时刻释放声明的内存,而不是在运行时之后。所以对我来说,只剩下一个问题:

操作系统会在某个时候回收已声明(但未使用)的内存吗?或者我必须自己管理内存(用new and delete)在运行时?


我不确定问题是什么,但我认为你做错了什么。您能否提供一个独立的示例来说明该问题?该示例程序编译并运行,析构函数被调用:

#include <boost/asio.hpp>
#include <functional>
#include <iostream>
#include <memory>

struct T
{
    T()
    {
        std::cerr << "T::T()\n";
    }

    ~T()
    {
        std::cerr << "T::~T()\n";
    }
};

void f(std::shared_ptr<T>&)
{
}

int main()
{
    using namespace boost::asio;
    io_service ios;
    ios.post(std::bind(&f, std::make_shared<T>()));
    ios.run();
}

您可以在此处查看输出:http://melpon.org/wandbox/permlink/0fkIAnoMXDOeedx7 http://melpon.org/wandbox/permlink/0fkIAnoMXDOeedx7

输出:

T::T()
T::~T()
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Boost::asio 和 boost::bind:Functor 内存永远不会被释放 的相关文章

随机推荐

  • 从 setter 方法返回 *this 时,对象变得不可变

    我正在了解这个指针 它包含调用该函数的当前对象的地址 但是当我从成员函数返回当前对象时 我对这个指针有疑问 include
  • foreach、doParallel 和随机生成

    考虑使用并行的非常基本 且效率低下 的代码foreach用于生成随机值 cl lt makeCluster 2 registerDoParallel cl foreach i 1 100 dopar rnorm 1 它是否正确 或者是否需要
  • Laravel Collection 与 groupby、count 和 sum

    我正在努力让一个集合上的 groupby 工作 我还没有得到这个概念 我正在从玩家的表中提取结果集合 雄辩的集合将包含如下数据 player id gt 1 opposition id gt 10 result gt won points
  • 带进度条的可可文件上传

    就问题而言 这确实是一个双重打击 因为确实有两个独立的问题 但它们有点属于在一起 第一个问题 我将如何使用 POST 上传文件 我已经有一个包含文件内容的 NSData 对象 同时在NSProgressIndicator 就像可以做 byt
  • Laravel 5 - 图像验证不起作用

    我使用 Laravel 5 Validator 来验证头像 我的规则如下所示 validator Validator make Request all avatar gt required image max 1000 我正在尝试上传文件
  • 向 ggmap 添加一堆箭头

    我正在绘制一张地图 它应该覆盖来自数据集的多个 gt 400 箭头 其中每个箭头的起点和终点都有纬度 经度对 这是使用 dput 的数据子集 df lt structure list Lat c 49 34054 49 34068 49 3
  • 将轴刻度标签中的一个字符更改为斜体,同时保留多行[重复]

    这个问题在这里已经有答案了 I have a geom col from ggplot2 with labels for categorical axis ticks like below 该图是使用以下代码创建的 library tidy
  • 用java创建一个简单的规则引擎

    我正在探索用 Java 创建简单业务规则引擎的不同方法 我需要向客户展示一个简单的 Web 应用程序 让他配置一堆规则 规则库的示例可能如下所示 这是例子 IF PATIENT TYPE A AND ADMISSION TYPE O SEN
  • RTF 行结束转换出现意外结果

    If txtLog is a RichTextBox http msdn microsoft com en us library system windows forms richtextbox aspx控制 Dim text hi vbC
  • 如何计算给定三个点的抛物线的顶点

    我有三个 X Y 点 形成一条抛物线 我只需要计算经过这三个点的抛物线的顶点是什么 最好是一种快速的方法 因为我必须做很多这样的计算 询问科学家 网站提供这个答案 http www newton dep anl gov askasci ma
  • 如何打印 Node WebKit 版本

    如果我想检查哪个节点WebKit https github com nwjs nw js我正在使用的版本 我将如何从命令行执行此操作 要了解应用程序中node webkit的版本 以便确定某些API是否可用 可以使用 process ver
  • 循环访问 ARM 模板中的值

    我已经花了一天多的时间来解决 ARM 模板遇到的问题 并且似乎陷入困境 所以询问 SO 以防有人可以提供帮助 为了描述该问题 我有一个现有的 Azure Key Vault 设置 并希望向该资源组添加许多访问策略 出于参考目的 以下是用于添
  • 如何使文件系统缓存失效?

    我想测量 优化应用程序的 冷启动 启动性能 如果不实际重新启动就很难做到这一点 这显然不是一个理想的解决方案 有没有一种方法可以使整个系统的文件缓存无效 以便映射的页面访问实际上导致磁盘访问 以便我可以测量程序启动所需的时间 信息 我非常需
  • 如何使用 perl 将完整路径转换为相对路径?

    我在 Perl 程序的两个变量中拥有文件的完整路径和其父目录之一的完整路径 什么是计算文件相对于父目录的相对路径的安全方法 需要在 windows 和 unix 上工作 e g filePath full path to my file p
  • 为什么需要将地图类型转换为列表以将其分配给 pandas 系列?

    我刚刚开始学习 pandas 的基础知识 有一件事让我思考 import pandas as pd data pd DataFrame Column1 A B C data Column2 map str lower data Column
  • 帮助解决 System.BadImageFormatException:

    在通过联系本地 Web 服务的 NET 3 5 SP1 项目进行调试时 我收到了异常 System BadImageFormatException 错误的类令牌 当然 关于导致异常的原因并没有更多细节 我可以看出发生这种情况的方法 与调用者
  • 无法应用插件 [id 'forge']

    这是一个延续这个问题 https stackoverflow com questions 58312064 upgrading gradle我的第一个问题已经解决了 但是新的问题又出现了 按照其中提到的教程 解决了一些错误后 现在当我尝试运
  • 没有收到所有 ICMP 超时消息:为什么?

    我正在使用 Scapy 重播一些转储的数据包 其中我更改了 TTL 值 即使 TTL 1 我也得到了非常奇怪的结果 当我分别运行测试时间时 我可以得到大约 40 到 95 的数据包回复了 ICMP 超时消息 然后 我可以递归地重放未应答的数
  • 使用多个列名的 SQLAlchemy 连接语法

    这是我想要执行的以下 sql 查询 并且在命令行上完美运行 select from table1 join table2 using col1 col2 我无法弄清楚如何使用 SQLAlchemy 执行此操作 任何帮助将不胜感激 表之间没有
  • Boost::asio 和 boost::bind:Functor 内存永远不会被释放

    我的代码正在分配内存并且从不释放它 即使它应该 至少在我看来 标题看起来像这样 typedef boost asio ssl stream