基本指南 从内存算法到托管内存片段 分配器和容器 Boost.Interprocess的性能 |
当构建Boost.Interprocess架构时,我采用了一些基本指南,它们被总结为以下几点:
Boost.Interprocess构建于三个基本类上:内存算法,片段管理器,托管内存片段:
内存算法(The memory algorithm) 片段管理器(The segment manager) Boost.Interprocess托管内存片段(managed memory segments) |
memory algorithm是一个对象,它被置于共享内存/内存映射文件片段的头几个字节中。memory algorithm能够返回此片段的部分至用户,并标记它们为已用,并且用户能够返回这些部分至memory algorithm以便memory algorithm再次标记它们为空闲。尽管有一个例外:一些超过内存算法对象尾部的字节被保留,并且不能被用于动态分配。这些“保留”区域将被用于放置其他额外的对象在一个众所周知的地方。
总结一下,memory algorithm具有和标准C库函数malloc/free相同的使命,但它仅能返回其置于的片段的部分。一个内存片段的布局可能是:
memory algorithm照顾到了内存同步,就好像malloc/free保证两个线程能同时调用malloc/free。它通常采用放置一个进程间共享的互斥量做为memory algorithm成员的方式实现。需要小心的是memory algorithm完全不了解内存片段(如果它是共享内存、共享内存文件等等)。对memory algorithm来说,内存片段仅是一块固定大小的内存缓冲区而已。
memory algorithm也是其余Boost.Interprocess框架(片段管理器、分配器、容器等)的一个配置点,因为它定义了两种基本类型做为成员类型定义:
typedef /*implementation dependent*/ void_pointer; typedef /*implementation dependent*/ mutex_family;
void_pointer类型定义定义了指针类型,它将被用在Boost.Interprocess框架(片段管理器、分配器、容器等)中。如果memoryalgorithm准备放置入映射在不同基地址上的共享内存/内存映射文件中时,此指针类型将被定义为offset_ptr<void>或一个类似的相对指针。如果memory algorithm将被与固定地址映射一起使用,void_pointer能被定义为void*。
Boost.Interprocess memory algorithm其余的接口在Writing a new shared memory allocation algorithm 章节中描述。做为memory algorithm的例子,你可以看simple_seq_fit或 rbtree_best_fit类的实现。
segment manager是一个对象,它也被置于托管内存片段(共享内存、内存映射文件)的头几个字节中,它构建于memory algorithm之上,提供了更复杂的服务。为什么segment manager和memory algorithm能同时置于片段的头几个字节中呢?这是因为segment manager包含了memory algorithm:真相是memory algorithm嵌入在segment manager中:
segment manager初始化memory algorithm,并且告诉内存管理器它不使用此部分内存,这块内存用于其余segment manager的成员的动态分配。segment manager的其他成员是一个递归互斥量(由memory algorithm的mutex_family::recursive_mutex类型定义成员定义)和两个索引(maps):一个用于执行具名分配,另一个用于执行“唯一实例”分配。
用于在索引中存储键值对(pair)的内存也是通过memory algorithm分配的,因此我们可以告诉大家,内部索引与构建在内存片段上的普通用户对象是相似的。其余用于存储对象名称、对象自身和构造/析构元数据的内存则在一个单独的allocate()调用中采用memory algorithm分配。
如上示,segment manager完全不了解共享内存/内存映射文件。segment manager本身不分配内存片段部分,它只是调用memory algorithm从剩余的内存片段中分配所需的内存。segment manager是一个构建在memory algorithm之上的类,它提供具名对象构建、唯一实例构建以及很多其他服务。
segment manager在Boost.Interprocess中是由segment_manager类实现的。
template<class CharType ,class MemoryAlgorithm ,template<class IndexConfig> class IndexType> class segment_manager;
如上示,segment manager非常通用:我们能指定用于区分具名对象的字符类型,我们能指定动态控制内存片段部分的memory algorithm ,并且我们也能指定存储映射(名指针,对象信息)的索引类型。我们能构建我们自己的索引类型,就好像Buildingcustom indexes 章节中解释地一样。
构建共享内存/内存映射文件的Boost.Interprocessmanaged memory segments放置segment manager并且发送用户的请求至segment manager。例如,basic_managed_shared_memory 是一个Boost.Interprocess托管内存片段,它与共享内存一起工作。basic_managed_mapped_file与内存映射文件一起工作......。
基本上,Boost.Interprocess managed memory segment的接口与segment manager相同,但它也提供了函数来“打开”、“创建”或“打开或创建”共享内存/内存映射文件片段并且初始化所有需要的资源。托管内存片段类不是构建在共享内存或内存映射文件中,它们是通常的C++类,存储了一个segment manager(构建在享内存或内存映射文件上)的指针。
此外,managed memory segments提供了特定的函数:managed_mapped_file提供函数用于刷新内存内容至文件,managed_heap_memory提供函数用于扩展内存,……
大部分Boost.Interprocess managed memory segments的函数能够在所有托管内存片段间共享,因为很多时候它们仅发送函数至segment manager。基于此,在Boost.Interprocess中,所有的托管内存片段都派生于一个共同的类,此类实现了内存独立(memory-independent)函数(共享内存、内存映射文件):boost::interprocess::ipcdetail::basic_managed_memory_impl。
派生于此类,对不同的内存后端,Boost.Interprocess实现了数个托管内存类:
Boost.Interprocess分配器 Boost.Interprocess 独立存储池的实现 Boost.Interprocess自适应池的实现 Boost.Interprocess容器 |
Boost.Interprocess的类STL(STL-like)分配器是相当简单的,且遵从通常的C++分配器方法。通常,STL容器的分配器基于new/delete操作之上,在此之上它们实现了池(pools)、竞技场(arenas)和其他分配技巧。
在Boost.Interprocess分配器中,方法是相似的,但是所有分配器都是基于segment manager。segment manager是唯一一个提供从简单内存分配到具名对象创建的。Boost.Interprocess分配器总是存储一个segment manager指针,以便它们能从内存片段获取内存或在分配器间共享普通池。
正如你能想到的,分配器的成员指针不是原始指针,而是由segment_manager::void_pointer定义的指针类型。此外,Boost.Interprocess分配器的指针类型定义也与segment_manager::void_pointer具有相同的类型。
这意味着如果我们的分配器算法定义 void_pointer为offset_ptr<void>, boost::interprocess::allocator<T>将存储一个offset_ptr<segment_manager> 指向segment manager,且boost::interprocess::allocator<T>::pointer类型将是offset_ptr<T>。这样,Boost.Interprocess分配器能被置于segment manager托管的内存片段中,即共享内存、内存映射文件等。
独立存储池是简单的,它遵从经典独立存储算法。
内存池由private_node_pool and shared_node_pool类实现。
自适应池是独立链表的一个变种,但它们具有更复杂的方法:
自适应池由 private_adaptive_node_pool and adaptive_node_pool类实现。
Boost.Interprocess容器是boost::interprocess名空间中标准STL容器的对应,但具有下面一些细节:
原始内存分配器的性能 具名分配器的性能 |
此小节尝试解释Boost.Interprocess的性能特性,以便如果你需要更好性能时能优化Boost.Interprocess的使用。
使用Boost.Interprocess,你能有两种类型的原始内存分配器:
如果你认为这种内存分配是你应用程序的一个瓶颈,你有如下的替代方案:
Boost.Interprocess允许与两个线程写入到一个共同的结构相同的并行,除了当用户创建/搜索命名/唯一对象时。创建一个具名对象的步骤如下:
当使用对象名销毁一个具名对象时(destroy<T>(name)),步骤如下:
当使用对象指针销毁一个具名对象时(destroy_ptr(T *ptr)),步骤如下:
如果你认为性能还不够好,你还有如下替代方案: