设为首页 加入收藏

TOP

C++ Primer 学习笔记_100_特殊工具与技术 --优化内存分配[续2](一)
2015-07-20 17:54:00 来源: 作者: 【 】 浏览:5
Tags:Primer 学习 笔记 _100_ 特殊 工具 技术 优化 内存 分配

特殊工具与技术

--优化内存分配[续2]

七.一个内存分配器基类

预先分配一块原始内存来保存未构造的对象,创建新元素的时候,可以在一个预先分配的对象中构造;释放元素的时候,将它们放回预先分配对象的块中,而不是将内存实际返还给系统。这种策略常被称为维持一个自由列表。可以将自由列表实现为已分配但未构造的对象的链表。

我们将定义一个名为 CachedObj 的新类来处理自由列表。像 QueueItem 这样希望优化其对象分配的类可以使用 CachedObj 类,而不用直接实现自己的 new 和 delete 成员。

CachedObj 类有简单的接口:它的工作只是分配和管理已分配但未构造对象的自由列表。这个类将定义一个成员 operator new,返回自由列表的下一个元素,并将该元素从自由列表中删除。当自由列表为空的时候,operator new 将分配新的原始内存。这个类还定义 operator delete,在撤销对象时将元素放回自由列表.

希望为自己的类型使用自由列表分配策略的类将继承 CachedObj 类,通过继承,这些类可以使用 CachedObj 类的 operator new 和 operator delete 定义,以及表示自由列表所需的数据成员。因为打算将 CachedObj 类作为基类,所以将给它一个 public 虚析构函数。

正如我们将看到的,CachedObj 只能用于不包含在继承层次中类型。与成员 new 和 delete 操作不同,CachedObj 类没有办法根据对象的实际类型分配不同大小的对象:它的自由列表保存单一大小的对象。因此,它只能用于不作基类使用的类,如 QueueItem 类。

由 CachedObj 类定义并被它的派生类继承的数据成员是:

? 指向自由列表表头的 static 指针。

? 名为 next、 从一个 CachedObj 对象指向另一个 CachedObj 对象的指针。

next 指针将元素链入自由列表。从 CachedObj 类派生的每个类型都包含自己的类型特定的数据,加上一个从 CachedObj 基类继承的指针。每个对象具有由内存分配器使用但被继承类型自己不用的一个额外指针,对象在使用的时候,该指针无意义且不使用;对象可供使用并在自由列表中的时候,就使用 next 指针来指向下一个可用的对象。

如果使用 CachedObj 类来优化 Screen 类的分配,Screen 类型的对象(概念上)看起来如图所示:

\

1.CachedObj类

template 
  
   
class CachedObj
{
public:
    void *operator new(std::size_t);
    void operator delete(void *,std::size_t);
    virtual ~CachedObj() {}

protected:
    T *next;

private:
    static void add_to_freelist(T *);
    static std::allocator
   
     alloc_mem; static T *freeStore; static const std::size_t chunk; };
   
  

[说明]

new 和 delete 成员分别从自由列表取走对象和将对象返回到自由列表。

static 成员管理自由列表。这些成员声明为 static,是因为只为所有给定类型的对象维持一个自由列表。freeStore 指针指向自由列表的表头。名为chunk 的成员指定每当自由列表为空时将分配的对象的数目。最后,add_to_freelist 函数将对象放在自由列表,operator new 使用这个函数将新分配的对象放到自由列表,删除对象的时候,operator delete 也使用该函数将对象放回自由列表。

2.使用CachedObj

当继承 CachedObj 类的时候,用来实例化 CachedObj 类的模板类型将是派生类型本身。

为了优化 Screen 类的内存管理,我们将 Screen 声明为:

class Screen : public CachedObj
  
   
{
    //...
};
因为QueueItem是一个模板类型,从CachedObj派生它有些复杂:
template 
   
     class QueueItem : public CachedObj< QueueItem
    
      > { //... };
    
   
  


我们的类不需要其他改变。现在 QueueItem 类具有自动内存分配,这个内存分配使用自由列表减少创建新的 Queue 元素时需要的分配数目。

3.分配怎样工作

因为我们从 CachedObj 类派生 QueueItem 类,任何使用 new 表达式的分配,如 Queue::push: 中的调用:

QueueItem
  
    *pt = new QueueItem
   
    (val); 
   
  

分配并构造一个新的 QueueItem 对象。每个表达式

1)使用 QueueItem ::operator new 函数从自由列表分配一个对象。

2)为类型 T 使用元素类型的复制构造函数,在该内存中构造一个对象。

类似地,当像 delete pt这样删除一个 QueueItem 指针的时候,运行 QueueItem 析构函数清除指向的对象,并调用该类的 operator delete,将元素所用的内存放回自由列表。

4.定义operater new

operater new 成员从自由列表返回一个对象,如果自由列表为空,new必须首先分配chunk数目的内存:

template 
  
   
void *CachedObj
   
    ::operator new(std::size_t sz) { if (sz == sizeof(T)) throw std::runtime_error ("CacheObj: wrong size object in operator new"); if (!freeStore) { T *array = alloc_mem.allocator(chunk); for (size_t i = 0; i != chunk; ++i) { add_to_freelist(&array[i]); } } T *p = freeStore; freeStore = freeStore -> CachedObj
    
     ::next; return p; }
    
   
  

operator new 函数检查自由列表中是否有对象,如果没有,它就请求allocator 成员分配 chunk 个新的未构造对象,然后,它通过新分配的对象进行迭代,设置 next 指针。调用了 add_to_freelist 函数之后,自由列表上的每个对象除了将保存下一个可用对象的地址 next 指针之外,将是未构造的。自由列表如图所示:

\

在有可用对象可以分配的保证之下,operator new 返回自由列表上第一个对象的地址,将 freeStore 指针重置为指向自由列表上下一个元素。被返回的对象是未构造的。因为从 new 表达式调用 Z??http://www.2cto.com/kf/ware/vc/" target="_blank" class="keylink">vcGVyYXRvciBuZXejrMv50tQgbmV3ILHttO/Kvb2ruLrU8Lm51Oy21M/zoaM8L3A+PHA+IDwvcD48cD41Lrao0uVvcGVyYXRlciBkZWxldGU8L3A+PHA+CW9wZXJhdG9yIGRlbGV0ZSCzydSx1ru4utTwudzA7cTa

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇hdu 3879 hdu 3917 构造最大权闭.. 下一篇leetcode 之 Recover Binary Sear..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: