【发布时间】:2016-04-28 11:22:58
【问题描述】:
我的代码正在分配内存并且从不释放它,即使它应该(至少在我看来)。
标题如下所示:
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
}
所以当我调用 Object.functionOne() 时,内存被分配给 Object.ioService_ 对象,以便能够调用绑定的异步方法。然后在循环之后,接受器上所有未决的异步操作都将被取消。只要 Object.ioService_.run() 被调用,相应的处理程序就会被调用(我一直在测试它)。但是由于某种原因,分配的内存没有被释放。那么有人可以解释一下为什么内存没有被释放并给我一个提示如何释放它?
顺便说一句:我正在开发 debian 并查看 /proc/self/status -> VmRSS 以了解使用的内存。
@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 的引用之后,也不会被释放?
我最终解释我的担忧的方法(4 月 28 日编辑)
好的,我做了一个可运行的例子,这表明了我的担忧: 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
更疯狂的是,在我自己的本地实现中,我得到以下输出:
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,这可能会让您感到困惑,但我的问题不是我的示例中是否发生内存泄漏以及在何处发生内存泄漏。这是关于结合 ioService 对象的内存分配。首先我认为,声称的内存正在无限增加。我做了最后一种方法来理解这种行为并得出结论,内存管理很好。内存不会被操作系统回收,但程序的内存分配正在收敛到一个限制,这对我来说很好。所以这个问题不在我的范围内。
Example: Converging memory consumption
最让我不安的是,我的本地实现表现出略有不同的行为。当 ioService 对象完成其工作并重置时,操作系统回收了内存,这符合我的期望。
所以总结所有观察:
分配的内存由 C++ 运行时和操作系统管理。直接观察分配过程非常困难(即使不是不可能?),因为它经过优化以减少对新内存页面的请求量,这意味着分配和释放的内存可能不会立即重新分配由操作系统。
为了向我指出这种行为的关键点,我想描述一下我的程序的用法:我正在开发一个服务器应用程序,这意味着程序应该运行无限长的时间。如果程序在某个时间要求大量的峰值内存,那完全没问题,但它需要在运行时的某个时间点释放所要求的内存,而不是在运行时之后。所以对我来说,只剩下一个问题了:
操作系统是否会在某个时候回收已声明的(但未使用的)内存?还是我必须在运行时自己管理内存(使用 new 和 delete)?
【问题讨论】:
-
这个服务器接受了多少个连接?
-
@Nim 无。这只是消耗的内存,只需构造 sslSocket 并添加异步操作即可。
-
好吧 - 处理程序仅在有连接时才执行,否则它只会保留套接字直到有接受 - 无论如何 - 请参阅我的答案 - 您使用 asio 和异步操作的方法是坏了..
-
@Nim 自从我调用 acceptor.cancel() 后处理程序被执行,所以所有待处理的操作都会在 ioService_.run() 后立即中止i> 被调用。是的,我也实施了典型的方法,我的例子只是为了突出我的问题。谢谢你的耐心:-)
-
..ahh - 错过了,是的 - 它应该被中止。您能否将 ssl 套接字包装在一个简单的类中,并查看该类的析构函数是否被触发。如果某个共享指针的某处有悬空引用,我会感到非常惊讶......
标签: c++ memory boost boost-asio boost-bind