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
傳遞給封裝類,供重載的自由內存分配函數調用, 封裝類的第二個參數傳入,做爲異步操做結束後調用的回調函數.