天天看点

ACE的内存分配介绍

一、内存分配器相关

ACE_Allocator

基类

ACE_New_Allocator : public ACE_Allocator

传统的new和delete的动态内存分配器,主要方法:

malloc 分配一定大小的内存,实质就是new char[nbytes];

calloc 同上,但带内存初始化

free 释放指定的内存块,实质就是delete[] ptr;

ACE_Static_Allocator_Base : public ACE_Allocator

静态内存分配器,一次性分配一个大内存,比如200M,然后在200M内分配(已经不能叫分配了)指定大小的内存块

成员:

char *buffer_; /// 缓冲区首地址

size_t size_;  /// 缓冲区的大小

size_t offset_;/// 当前分配位置

主要方法:

malloc 分配一定大小的内存,实质就是buffer_ + offset_ + nbytes,当超过size_时分配失败

calloc 同上,但带内存初始化

free 释放指定的内存块,实质是空操作

从实质来看只适合预知消耗内存大小而且一般不进行释放操作的情况下,因为释放后的内存没有得到应用

template <class MALLOC>

class ACE_Allocator_Adapter : public ACE_Allocator

内存分配适配器,对各种各样的内存分配类进行适配,使之符合ACE_Allocator接口,MALLOC是具体的内存

分配实现,比如上面的ACE_New_Allocator,ACE_Static_Allocator_Base和用户自定义的分配器

二、空闲列表

template <class T>

class ACE_Cached_Mem_Pool_Node

支持可缓存的对象节点,可用于空闲链表(free_list),实现了set_next和get_next

成员:

ACE_Cached_Mem_Pool_Node<T>* next_;

template <class T>

class ACE_Free_List

模版基类

主要方法:

add 加入一个节点到空闲链表

remove 移除一个空闲节点(给用户使用)

size 链表当前有效的空闲节点个数

resize 重新设置链表节点个数

template <class T, class ACE_LOCK>

class ACE_Locked_Free_List : public ACE_Free_List<T>

带锁策略的空闲列表,其实除了锁策略,它还有其他几个特点:

1、可以定制为一个纯空闲列表,就是内部不调用new/delete,由外部处理,在构造时将mode传入

ACE_PURE_FREE_LIST即可,默认是ACE_FREE_LIST_WITH_POOL,表示内部在需要时可以调用new/delete进行操作;

2、支持水位(water mark)的概念,一个低水位(lwm),一个高水位(hwm),水位只对mode为ACE_FREE_LIST_WITH_POOL时起作用

3、当节点不够时,支持一次性递增inc个节点(N由用户在构造时传入),只对mode为ACE_FREE_LIST_WITH_POOL时起作用

主要方法:

add 加入一个节点(可能是用户用完了的节点),如果mode为ACE_PURE_FREE_LIST或者mode为ACE_FREE_LIST_WITH_POOL而size<hwm时允许加入,否则delete掉

remove 从空闲链表移除一个节点(给用户使用),当mode为ACE_FREE_LIST_WITH_POOL而size<=lwm时,表示节点数过少,系统会分配inc个节点出来以解燃眉之急,如果是ACE_PURE_FREE_LIST模式,当节点数为0时,remove将返回NULL

resize 当mode为ACE_FREE_LIST_WITH_POOL时有意义,resize>size时,分配resize-size个节点,否则释放size-resize个节点

举例:

class MyClass

{

 int dummy;

public:

 MyClass() : dummy(99) {}

 void foo()

 {

  std::cout<<dummy<<std::endl;

 }

};

void test()

{

 ACE_Locked_Free_List< ACE_Cached_Mem_Pool_Node< MyClass >, ACE_SYNCH_NULL_MUTEX>  freeList; // 用ACE_SYNCH_NULL_MUTEX不需要同步,等同于单线程

 // 取出一个(分配一个)

 ACE_Cached_Mem_Pool_Node< MyClass >* node = freeList.remove();

 MyClass* mc = node.addr();

 // 用一下

 mc->foo();

 // 不用了,释放掉

 freeList.add(node);

}

三、各种内存分配策略

template <class T, class ACE_LOCK>

class ACE_Cached_Allocator : public ACE_New_Allocator

有缓存功能的动态分配器,采用空闲链表进行节点管理,空闲链表的mode为ACE_PURE_FREE_LIST,即真正的new/delete由ACE_Cached_Allocator自己操作,

构造时可指定初始化T节点的个数,节点的大小由sizeof(T)决定,同时进行字节对齐。

注意:

该分配器内部对T类型没有进行构造和析构,所以不适合class使用,可用于struct,并且该分配器不支持自动增大内存区(也就是pool_成员在构造时就确定了)

,当内存不够时,分配会失败。

主要成员:

char *pool_; /// 内存块

ACE_Locked_Free_List<ACE_Cached_Mem_Pool_Node<T>, ACE_LOCK> free_list_;  /// 空闲节点管理

主要方法:

malloc 分配一个T节点,实际就是 return free_list_.remove()->addr();

calloc 同上,但会初始化内存数据

free 释放一个T节点,实际就是 free_list_.add ((ACE_Cached_Mem_Pool_Node<T> *) ptr);

template <class ACE_LOCK>

class ACE_Dynamic_Cached_Allocator : public ACE_New_Allocator

同上,但是没有T模版参数,多了一个成员chunk_size_,每个节点的大小由用户自行定义,同样不存在构造和析构功能,仅仅停留在固定节点大小的缓冲区的管理,内部没有进行字节对齐。

template <size_t POOL_SIZE>

class ACE_Static_Allocator : public ACE_Static_Allocator_Base

基于堆栈的静态内存分配器,POOL_SIZE为堆栈大小