2009-10-27 58 views
4

我正在使用自定義分配器來計算多個容器中的內存使用情況。目前我使用一個靜態變量來說明內存使用情況。我怎樣才能將這個帳戶分離到多個容器中,而不必重寫分配器來使用不同的靜態變量?使用自定義分配器的帳戶內存使用情況


static size_t allocated = 0; 


    template <class T> 
    class accounting_allocator { 
    public: 
     // type definitions 
     typedef T  value_type; 
     typedef T*  pointer; 
     typedef const T* const_pointer; 
     typedef T&  reference; 
     typedef const T& const_reference; 
     typedef std::size_t size_type; 
     typedef std::ptrdiff_t difference_type; 
     //static size_t allocated; 

     // rebind allocator to type U 
     template <class U> 
     struct rebind { 
      typedef accounting_allocator<U> other; 
     }; 

     // return address of values 
     pointer address (reference value) const { 
      return &value; 
     } 
     const_pointer address (const_reference value) const { 
      return &value; 
     } 

     /* constructors and destructor 
     * - nothing to do because the allocator has no state 
     */ 
     accounting_allocator() throw() { 
     } 
     accounting_allocator(const accounting_allocator&) throw() { 
     } 
     template <class U> 
     accounting_allocator (const accounting_allocator<U>&) throw() { 
     } 
     ~accounting_allocator() throw() { 
     } 

     // return maximum number of elements that can be allocated 
     size_type max_size() const throw() { 
     // std::cout << "max_size()" << std::endl; 
      return std::numeric_limits<std::size_t>::max()/sizeof(T); 
     } 

     // allocate but don't initialize num elements of type T 
     pointer allocate (size_type num, const void* = 0) { 
      // print message and allocate memory with global new 
      //std::cerr << "allocate " << num << " element(s)" << " of size " << sizeof(T) << std::endl; 
      pointer ret = (pointer)(::operator new(num*sizeof(T))); 
      //std::cerr << " allocated at: " << (void*)ret << std::endl; 
      allocated += num * sizeof(T); 
      //std::cerr << "allocated: " << allocated/(1024*1024) << " MB" << endl; 
      return ret; 
     } 

     // initialize elements of allocated storage p with value value 
     void construct (pointer p, const T& value) { 
      // initialize memory with placement new 
      new((void*)p)T(value); 
     } 

     // destroy elements of initialized storage p 
     void destroy (pointer p) { 
      // destroy objects by calling their destructor 
      p->~T(); 
     } 

     // deallocate storage p of deleted elements 
     void deallocate (pointer p, size_type num) { 
      // print message and deallocate memory with global delete 
#if 0 
      std::cerr << "deallocate " << num << " element(s)" 
        << " of size " << sizeof(T) 
        << " at: " << (void*)p << std::endl; 
#endif 
      ::operator delete((void*)p); 
      allocated -= num * sizeof(T); 
     } 
    }; 
    template<> 
    class accounting_allocator<void> 
    { 
    public: 
     typedef size_t  size_type; 
     typedef ptrdiff_t difference_type; 
     typedef void*  pointer; 
     typedef const void* const_pointer; 
     typedef void  value_type; 

     template<typename _Tp1> 
     struct rebind 
     { typedef allocator<_Tp1> other; }; 
    }; 


    // return that all specializations of this allocator are interchangeable 
    template <class T1, class T2> 
    bool operator== (const accounting_allocator<T1>&, 
        const accounting_allocator<T2>&) throw() { 
     return true; 
    } 
    template <class T1, class T2> 
    bool operator!= (const accounting_allocator<T1>&, 
        const accounting_allocator<T2>&) throw() { 
     return false; 
    } 
+0

你的意思是你想爲每個容器類型都有一個單獨櫃檯?如果是這樣,您可以簡單地將容器類型作爲模板參數。這樣,將爲每種類型的容器生成單獨的計數器變量。 – 2009-10-27 09:39:39

+0

我打算爲每個使用此分配器的容器設置一個帳戶。我想過用靜態分配的計數成員構建幾個類,但我不確定是否可以將此類作爲模板參數傳遞給分配器,但在嘗試重新綁定等時只會使用一個模板參數,而不會失敗。 – piotr 2009-10-27 09:51:46

回答

0

將 「分配靜態的size_t」 的聲明到類defininition。每個模板實例都將有一個單獨的計數器在該模板的所有對象之間共享。

6

如果您的意思是您希望爲每個容器類型單獨計數器,則可以簡單地將容器類型作爲模板參數並取消註釋static size_t allocated,因此它是靜態成員變量。這樣,將爲每種類型的容器生成單獨的計數器變量。

如果你說你要爲每個實例的容器一個獨立的計數器,你需要做size_t allocated非靜態成員變量。問題是,您還需要某種鉤子,以便您可以從每個容器外部訪問分配計數器。 STL分配器設計使得難以做到這一點。一些STL容器有一個構造函數,可以讓你傳遞一個分配器的實例,但並不是所有的容器都支持這個。在支持此的容器上,可以在分配器類中包含對某個全局映射的引用,然後將分配器的實例傳遞給每個容器的構造器。然後,當你調用accounting_allocator::allocate()時,分配器會記錄它在全局映射中分配的字節數。儘管如此,我看不出如何輕鬆地將此信息與特定的容器實例相關聯,因爲分配器對象不知道它屬於哪個容器。

說實話,如果你只是收集調試信息,那麼定義一個非靜態的size_t allocated可能更簡單,並且accounting_allocator::allocate()只是將統計輸出到文件或stdout。或者,使用內存分析器工具查看您開發的平臺。

0

看我的代碼示例:

// uintptr_t represents an object address 
// as a numerical value. 
// you could use unsigned long insead if 
// sizeof(long) == sizeof(void*) on your system. 
struct AllocCounter { 
    static size_t *Register(uintptr_t uContainer) 
    { 
     // insert container address into map, and 
     // return an associated allocation counter. 
    } 
    static bool Unregister(uintptr_t uContainer) 
    { 
     // remove container address and the 
     // associated allocation counter from the map 
    } 
    static void DebugCounter(void) 
    { 
     // statistic of all container objects. 
    } 
protected: 
    static hash_map<uintptr_t, size_t> m_aCounter; 
}; 

此外,你可以容器或對象類名稱等與上述AllocCounter提高分配計數器關聯。

和容器例如:

class Container 
{ 
public: 
    Container(void) 
    { 
     m_pAllocCounter = AllocCounter::Register((uintptr_t)this); 
     .... 
    } 
    ~Container() 
    { 
     AllocCounter::Unregister((uintptr_t)this); 
    } 
    pointer ObjectAllocate(void) 
    { 
     pointer obj; 
     *m_pAllocCounter += sizeof *obj; 
     obj = new CObject; 
     return obj; 
    } 
    void ObjectDealloc(pointer pObj) 
    { 
     *m_pAllocCounter -= sizeof *pObj; 
     delete pObj; 
    } 
    .... 

private: 
    size_t *m_pAllocCounter; 
    .... 
};