socket_.async_read_some(boost::asio::buffer(data_),[](){ ... });
用asio实现网络编程一般的套路是单线程异步,对特定socket发起异步的读取操做,读取ok以后立刻再次发起对这个socket上的异步写入操做,反复执行; client经过传入异步函数回调函数来发起下一次的读/取操做, 而可调用对象(函数对象/lambda表达式)均可以等加成传入了一个类实例,asio负责对这个类实例存储和释放,默认的内存分配策略是operator new
, 能够想象, 在持续不断的异步调用的时候,内存的分配和释放也在持续进行,下降了性能开销也产生了内存碎片. 针对这个优化点,asio提供了内存分配的hook,能够用client内存分配策略替换系统默认的行为.html
asio用于定制化内存分配策略函数以下:程序员
以asio_handler_allocate
举例,my_handler就是回调对象的指针,能够看到,asio默认的内分分配策略是operator new
.面试
class my_handler; void* asio_handler_allocate(std::size_t size, my_handler* context) { return ::operator new(size); }
若是想实现针对回调函数内存分配策略的定制,须要干两个活儿:编程
operator ()
完成,异步操做完成后就会执行真是操做.asio_handler_allocate
和 asio_handler_deallocate
用于定制化内存分配策略.asio会对其进行调用.官方例子地址以下:Allocation网络
自定义内存分配策略的对象,提供内存分配和释放(allocate/deallocate)的成员函数.异步
// class handler_allocator // 提供字节对齐的内存地址,此空间分配在栈上, 用于提供给可调用对象实际的存储空间 typename std::aligned_storage<1024>::type storage_; // 空间是否在使用标记位 bool in_use_; // 用于传递至回调函数内,以供调用,deallocate实现相似 void* allocate(std::size_t size) { if (!in_use_ && size < sizeof(storage_)) { in_use_ = true; return &storage_; } else { // 若是内存已经被使用,则使用默认分配策略 return ::operator new(size); } }
支持内存分配策略的回调对象包装类. 注释中给出解释:socket
// Handler回调函数通用化,放到模板里面 template <typename Handler> class custom_alloc_handler{ public: // 传入内存分配器 和 回调对象 custom_alloc_handler(handler_allocation &a, Handler h) : allocator_(a), handler_(h) {} // 回调函数调用 template <typename ...Args> void operator()(Args&&... args) { handler_(std::forward<Args>(args)...); } }; ... private: // 保证全部的异步调用给回调函数分配的空间是同一份,因此声明为引用. handler_allocator &allocator_; Handler handler_;
这样,回调函数包装类就实现了对真实回调函数的封装,异步完成执行后,asio会调用包装类的operator ()
实现对真实回调函数的调用. 那么这个类如何利用内存分配器提供内存分配定制呢?
按照原理章节中描述,须要实现对两个自由函数的重载,仍然之内存分配函数为例,内存释放道理同样:async
template<typename Handler> void* asio_handler_allocate(std::size_t size, custom_alloc_handler<Handler>* this_handler) { // 调用回调封装对象中的内存分配器,实现定制化的内分分配策略. return this_handler->allocator_.allocate(size); }
custom_alloc_handler
辅助函数,用于构建实例类对象函数
template <typename Handler> inline custom_alloc_handler<Handler> make_custom_alloc_handler( handler_allocator& a, Handler h) { return custom_alloc_handler<Handler>(a, h); }
以上章节其实是对client端程序员不可见的,当构建一个异步的应用程序且须要对内存分配进行控制(空间复用),那么使用方式以下:性能
void do_read() { auto self(shared_from_this()); socket_.async_read_some(boost::asio::buffer(data_), // 把内存分配器兑现刚和真实的回调函数(这里用lambda)封装于customer_alloc_handler中 make_custom_alloc_handler(allocator_, [this, self](boost::system::error_code ec, std::size_t length) { if (!ec) { do_write(length); } })); }
其中,allocator
为外部声明的内存分配器对象,由于须要给全部的异步调用使用,所以须要保证异步调用做用域内有效; 能够看到,对于客户端来讲,可变的部分只有异步调用async_read_some
的第二个参数,其余地方没有改变,allocator
传递给封装类,供重载的自由内存分配函数调用, 封装类的第二个参数传入,做为异步操做结束后调用的回调函数.