Boost :: asio和boost :: bind:函子内存永远不会释放 [英] Boost::asio and boost::bind: Functor memory is never released

查看:122
本文介绍了Boost :: asio和boost :: bind:函子内存永远不会释放的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

My code is allocating memory and never freeing it, even though it should (at least in my opinion).

标题看起来像这样:

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

我的消息来源是这样的:

And my source like this:

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
}

因此,当我调用 Object.functionOne()时,内存将分配给 Object.ioService _ 对象,以便能够调用绑定的异步方法.然后,在循环之后,将取消接受器上所有未决的异步操作.调用 Object.ioService_.run()时,就会调用适当的处理程序(我一直在对此进行测试).但是由于某种原因,分配的内存不会被释放.所以有人可以解释一下,为什么内存没有被释放,并提示我如何释放它?

So when i call Object.functionOne(), memory is getting allocated to the Object.ioService_ object, in order to be able to call the bound asynchronous method. Then after the loop, all pending asynchronous actions on the acceptor are getting canceled. The appropriate handler is getting invoked as soon as Object.ioService_.run() is called (i've been testing that). BUT for some reason, the allocated memory does not get freed. So can someone please explain, why the memory is not getting deallocated and give me a hint how to free it?

顺便说一句:我正在研究debian,并查看/proc/self/status -> VmRSS 来回收已用的内存.

Btw.: I'm working on debian and looking at /proc/self/status -> VmRSS to whatch the used memory.

@Vinnie Falco

#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循环中的限制,您会发现,程序会保留大量内存,即使应在调用所有异步处理程序后释放它们.但是 sslSocket 对象没有被释放,这就是我的问题:为什么将内存(特别是为sslSocket分配的内存)绑定到函子 functionTwo ,即使调用了异步方法 fucntionTwo 并且没有留下对 sslSocket 的引用,也不会取消分配?

My question is not, if and why the destructor of T is called, this works as supposed to. But the behaviour concerning the used memory is strange. So if you increase the limit in the for loop, you will observe, that a lot of memory is getting reserved by the program, even though it should be released after all asnchronous handlers have been invoked. But the sslSocket objects are not getting deallocated, which is what my question is about: Why is the memory (specifically the memory allocated for the sslSocket), bound to the functor functionTwo, not deallocated, even after the asynchronous method fucntionTwo has been invoked and no reference to the sslSocket is left?

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

好的,我举了一个可运行的例子,表明了我的关注: 示例中的我的问题

Alright, i made a runnable example, that shows my concern: My Problem in an example

输出:

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

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

What's even more crazy is, that in my own local implementation I get the following output:

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

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

So it can clearly be seen: the memory is not freed, even after all asynchronous operations have been invoked.

摘要和已理解的行为(?)(最后编辑)

由于有些人可能会误会我的意思,所以我不认为我的代码中存在某种泄漏.我在代码示例 Leak 中命名了该结构,这可能使您感到困惑,但我的问题不是在示例中是否以及在哪里发生内存泄漏.它是关于与 ioService 对象结合使用的内存分配的.首先,我认为要求保护的内存会无限增加.我采取了最后一种了解这种行为的方法,并得出结论,内存管理很好.操作系统没有回收内存,但是程序的内存分配正在收敛到一个极限,这对我来说很好.因此,这个问题是我无法解决的.

As some of you might have missunderstood, i'm not thinking that there is some kind of a leak in my code. I named the structure in my code example Leak, which might have confused you, but my question is not if and where a memory leak occurs in my example. It's about the memory allocation in combination with the ioService object. First I thought, that the claimed memory is increasing infinitly. I made a last approach to understand this behaviour and came to the conclusion, that the memory management is fine. Memory is not reclaimed by the OS, but the program's memory allocation is converging to a limit, which is fine with me. So this problem is out of my way.

示例:聚合内存消耗

让我最困扰的是我的本地执行方式表现出略有不同的行为.当 ioService 对象完成其作业并重置后,OS回收了内存,这满足了我的期望.

What disturbed me most was that my local implemention showed a slightly different behaviour. There the memory was reclaimed by the OS, when the ioService object was done with its jobs and reset, which satisfied my expectations.

所以总结所有观察结果:

So to sum up all observations:

分配的内存由C ++运行时和操作系统管理.直接观察分配过程非常困难(即使不是不可能?),因为它已进行了优化以减少对新内存页面的请求量,这意味着分配和释放的内存可能不会立即重新分配通过操作系统.

The allocated memory is managed by the C++ Runtime and the OS. It's quite difficult (if not even impossible?) to directly observe the allocation procedure, since it's optimized to reduce the amount of requests for new memory pages, which means that allocated and freed memory might not be immidiatly reallocated by the OS.

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

To point out the critical point to me with this behaviour, i want to describe the usage of my program: I'm developing a server application, which means, that the program should run an infinit amount of time. If the program claims a lot of peak memory at some time, it's totaly fine, but it needs to release the claimed memory at some point in runtime, not after the runtime. So to me, there is only one question remaining:

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

Will the claimed (but unused) memory be reclaimed by the OS at some time? Or do I have to manage the memory on my own (with new and delete) in runtime?

推荐答案

花了我一段时间,但我终于设法自己解决了.

It took me a while, but i finally managed to work it out by myself.

因此,为澄清起见,请确保已理解我问题的根源: 我正在开发一个服务器应用程序,该应用程序将无限期地运行.该应用程序必须能够处理大量并发的传入连接.在某个时间点,负载可能达到峰值,从而导致我的应用程序占用了很多内存.然后过了一会儿,大多数传入的请求已被处理,导致许多对象在运行时被释放.由于操作系统不需要内存(我的应用程序是服务器上唯一的巨大内存消耗者),因此所有释放的内存都留在我的应用程序中,并且可以在其他时间点重用.这对我来说绝对没问题,但是某些客户和管理员可能会误将大量不断声明的内存误认为是内存泄漏应用程序.为避免这种情况,我想将一些未使用的内存手动移交给操作系统.在我的示例中, ioService 的绑定处理程序(例如,接受新连接)将在运行时释放,但操作系统不会回收适当的内存.因此,要手动执行此操作,我发现了以下解决方案:

So to clearify things, let's make sure, that the root of my problem is understood: I'm developing a server application, which is meant to run for an infinit amount of time. This application must be able to handle a lot of concurrent incomming connections. At some point in time, there may be a peak in load, leading to a lot of claimed memory to my application. Then after a while, most incomming requests have been processed, causing a lot of objects to be freed in runtime. Since the OS is in no need for memory (My application is the only huge memory consumer on the server), all freed memory stays with my application and can be reused at another point in time. This would be absolutely fine with me, but some customers and administrators might misinterpret the greater amount of constantly claimed memory as a memory leaking application. To avoid this, i wanted to hand some of the unused memory back to the OS manually. In my example, the bound handlers to the ioService (e.g. accepting a new connection) would be freed in runtime, but the appropriate memory won't be reclaimed by the OS. So to do this manually, i found the following solution:

在C/C ++中的Linux下释放未使用的堆内存:int malloc_trim(size_t pad)

可以在此处找到该文档.为简化起见,此方法将未使用的内存从堆释放到OS,这正是我一直在寻找的东西.我知道在内存优化方面,手动使用此功能可能很危险,但是由于我只想每隔几分钟就释放一次内存,因此我可以接受此性能问题.

The documentation can be found here. Simplified explained, this method releases unused memory from the heap to the OS, which is exactly what i've been searching for. I'm aware that under memory optimization aspects, the manual use of this function maybe dangerous, but since i only want to release the memory every few minutes, this performance issue is acceptable to me.

感谢大家的努力和耐心!

Thank you all for your efforts and patience!

这篇关于Boost :: asio和boost :: bind:函子内存永远不会释放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆