簡體   English   中英

STL C ++對象的內存分配

[英]Memory Allocation by STL C++ Objects

我使用malloc_stats()函數來顯示進程使用的“系統字節”和“使用中”字節的數量。 我想知道使用中的字節是否還包括STL C ++對象使用的內存,如map,vector,sets?

如果是,是否可以安全地假設這只是進程將使用的內存量?

這沒有在標准中指定,new可能會調用malloc。 在我使用過的實現中,確實如此。

做你想做的事情的最好方法是定義你自己的新運算符來計算分配的內存,或者像STL容器一樣使用會計分配器:

#include <memory>
#include <limits>
extern size_t allocated;
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);
    }
};

#if 0
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; };
};
#endif

// 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;
}
/************** accounting allocator end ***********/

使用new進行記帳的一個例子:雖然我更喜歡使用(3)malloc_hook和unordered_map

size_t used_mem = 0;
std::map<void*,size_t> acc;

void* operator new(size_t size) throw (std::bad_alloc)
{
    void *mem;
    if(size == 0)
        size = 1;
    mem = malloc(size);
    if(mem) {
        memset(mem, 0, size);
        used_mem += size;
        acc[mem] = size;
        return mem;
    }
    std::new_handler nh = std::set_new_handler(0);
    std::set_new_handler(nh);
    if (nh) {
        (*nh)();
        return (void*)0;
    } else {
        //return (void*)0;
        throw std::bad_alloc();
    }
}

void operator delete(void *mem) throw()
{
    std::map<void*,size_t>::iterator i = acc.find(mem);
    if( i != acc.end() ) {
        size_t size = i->second;
        used_mem -= size;
    }
    free(mem);
}

默認情況下,STL不需要使用malloc,但您可以傳入一個分配器來指定它。 請參閱Dobbs博士的這個例子

我的系統上沒有malloc_stats函數,但你可以通過創建一個1000000 int s的向量來運行一個簡單的測試(只是確保你保存所有的工作,以防萬一你不小心耗盡所有的RAM並崩潰你的系統 :-) )。

請注意,在許多操作系統上, malloc不是為程序分配內存的唯一方法。 例如,在Linux上,您(或C ++實現)可以跳過malloc()並使用較低級別的系統函數,如mmap()sbrk() 因此, malloc_stats可能不會告訴您程序正在使用的所有內存。 檢查getrusage為此。

你不能總是假設默認的分配器和operator new使用malloc ,但很可能所有都來自同一個池。 您詢問特定於Linux的函數這一事實使其成為這一特定上下文的安全假設。

其他人建議您定義自定義分配器類。 只有在每個STL容器聲明中將該分配器作為模板參數傳遞時,這才有效。 這是相當容易出錯的,因此我不建議將其作為簡單的分析策略。

至於第二個問題,不,除了STL容器之外的其他東西將分配內存。 例如, fstream以實現定義的方式創建I / O緩沖區。 algorithm某些函數會創建temporary_buffer對象,而不使用分配器。 temporary_buffer不是標准的一部分;它是原始HP / SGI STL的一部分。其他實現可能稱之為其他實現,但在任何情況下都允許某些函數分配臨時工作空間。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM