注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

gmd20的个人空间

// 编程和生活

 
 
 

日志

 
 

boost.function 和 asio异步操作的动态内存分配问题  

2012-08-02 23:28:24|  分类: 程序设计 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

1.   boost.function   对象比较大时,复制时需要从堆里面动态分配内存。这个感觉不是很好啊,按照boost文档的说法,他有个 small buffer的优化,可能function对象比较小的时候,是不需要动态分配的。不过我看的程序确实会有动态分配和销毁。 没看到什么好的解决办法,文档那个 cref传引用的用法应该用不上吧,只能尽量减少function对象的大小,不要绑定多的固定参数? 谁知道什么好告诉我一下吧。 

可以参考一下这个文章,

http://www.codeproject.com/Articles/18389/Fast-C-Delegate-Boost-Function-drop-in-replacement 


8月5号补充:

Efficient Use of Lambda Expressions and std::function

http://www.drdobbs.com/article/print?articleId=232500059&siteSectionName= 

void swap(const functionN& f);

Effects:

Interchanges the targets of *this and f.

另外,boost::function 也是支持 自定义allocator的

template<typename F, typename Allocator> functionN(F f, Allocator alloc);

Requires:

F is a function object Callable from this, Allocator is an allocator. The copy constructor and destructor of Allocator shall not throw.

Postconditions:

*this targets a copy of f if f is nonempty, or this->empty() if f is empty.

Effects:

If memory allocation is required, the given allocator (or a copy of it) will be used to allocate that memory.


在boost的代码里面 function_base.hpp 文件里面有一个function_allows_small_object_optimization 的类,是用于这个用途的。如果比较函数对象比较他是直接保存到一个union function_buffer 里面,否则就要从堆里面分配内存,然后那些赋值和销毁时的,动态内存分配和释放之类的操作,感觉代价有点大。boost里面也没有提供某些参数可以调整这个small object 优化的大小边界,function_buffer 是个union,应该不容易修改啊。

-相关代码如下:


/**
* Determine if boost::function can use the small-object
* optimization with the function object type F.
*/
template<typename F>
struct function_allows_small_object_optimization
{
BOOST_STATIC_CONSTANT
(bool,
value = ((sizeof(F) <= sizeof(function_buffer) &&
(alignment_of<function_buffer>::value
% alignment_of<F>::value == 0))));
};






// Function objects that fit in the small-object buffer.
static inline void
manager(const function_buffer& in_buffer, function_buffer& out_buffer,
functor_manager_operation_type op, mpl::true_)
{
functor_manager_common<Functor>::manage_small(in_buffer,out_buffer,op);
}

// Function objects that require heap allocation
static inline void
manager(const function_buffer& in_buffer, function_buffer& out_buffer,
functor_manager_operation_type op, mpl::false_)
{
if (op == clone_functor_tag) {
// Clone the functor
// GCC 2.95.3 gets the CV qualifiers wrong here, so we
// can't do the static_cast that we should do.
// jewillco: Changing this to static_cast because GCC 2.95.3 is
// obsolete.
const functor_type* f =
static_cast<const functor_type*>(in_buffer.obj_ptr);
functor_type* new_f = new functor_type(*f);
out_buffer.obj_ptr = new_f;
} else if (op == move_functor_tag) {
out_buffer.obj_ptr = in_buffer.obj_ptr;
in_buffer.obj_ptr = 0;
} else if (op == destroy_functor_tag) {
/* Cast from the void pointer to the functor pointer type */
functor_type* f =
static_cast<functor_type*>(out_buffer.obj_ptr);
delete f;
out_buffer.obj_ptr = 0;
} else if (op == check_functor_type_tag) {
const detail::sp_typeinfo& check_type
= *out_buffer.type.type;
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_TYPEID(Functor)))
out_buffer.obj_ptr = in_buffer.obj_ptr;
else
out_buffer.obj_ptr = 0;
} else /* op == get_functor_type_tag */ {
out_buffer.type.type = &BOOST_SP_TYPEID(Functor);
out_buffer.type.const_qualified = false;
out_buffer.type.volatile_qualified = false;
}
}

// For function objects, we determine whether the function
// object can use the small-object optimization buffer or
// whether we need to allocate it on the heap.
static inline void
manager(const function_buffer& in_buffer, function_buffer& out_buffer,
functor_manager_operation_type op, function_obj_tag)
{
manager(in_buffer, out_buffer, op,
mpl::bool_<(function_allows_small_object_optimization<functor_type>::value)>());
}

// For member pointers, we use the small-object optimization buffer.
static inline void
manager(const function_buffer& in_buffer, function_buffer& out_buffer,
functor_manager_operation_type op, member_ptr_tag)
{
manager(in_buffer, out_buffer, op, mpl::true_());
}



2.  asio的异步调用是会每次都调用  new 和delete来动态分配内存的。不过这个可以用过自定义内存分配器,用内存池的思想来避免。

Custom Memory Allocation

http://think-async.com/Asio/asio-1.5.0/doc/asio/overview/core/allocation.html 




8月29 号补充:

      尝试了一下,弄个固定大小内存块的内存池,因为多线程的关系还是不要锁的。自定义的内存分配器和自定义的vc内置的内存分配器没有多大的区别。用boost pool之类的,好像性能还变差了。 看到Andrei Alexandrescu有个视频说,除了那种非常特定环境下,自定义的内存分配器并不能比系统默认的堆管理器做的更好,通常的系统内置的非配器都是经过各种各样的优化和考验的,可以适应大多的应用场合,自己弄内存分配器大多情况下都是费力而不讨好。 看来确实如此!网上有人说经常动态分配内存可能会导致 “内存碎片”问题,但比较新的windows系统针对这个问题也有优化了,在比较小的内存块时都优化成固定大小块了,应该能一定程度上缓解这个问题。

      asio例子里面的自定义内存分配重复利用同一块,但很多时候,有很多操作并行执行的,这样并没有多大效果。不过现在代码里面申请空闲reqeust的时候的基于request的pool,应该还是不错的吧,也许这就是Andrei Alexandrescu所说的特定场合。

       google的tcmalloc 内存分配器听说很不错,基于 thread cache设计在多线程环境下性能比较好。下载最新的源码里面也是有文档说如何在windows在visual studio 项目里面使用的,想google 的chrome浏览器这些项目都是默认使用这个。听说链接他的dll之后,会在静态变量的初始化构造函数里面动态的替换系统自带的malloc函数(也有静态链接的办法,不过要修改系统自带的crt库好像)。 没看到有人测试和这个比较新的版本的visual studio自带的分配器的性能比较,好像对vc暂时支持也是很好,64位啊这些比较麻烦,我就不尝试了。

      不过编程的时候i还是尽量避免动态内存分配吧。看到的一个比较明显的问题就是,new delete比较多的话,page fault也是比较多的,之前的一个同事的库里面每个message都 需要new /delete,看到的程序的page fault 平均每秒5000个,觉得还是比较影响性能的吧。

  评论这张
 
阅读(918)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017