STL C ++对象的内存分配

时间:2010-05-21 05:40:21

标签: c++

我正在使用malloc_stats()函数来显示进程使用的“系统字节数”和“使用中”字节数。我想知道使用中的字节是否还包括STL C ++对象使用的内存,如map,vector,sets?

如果是,是否可以安全地假设这只是进程将使用的内存量?

4 个答案:

答案 0 :(得分:3)

标准中没有指定,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 ***********/

新会计的一个例子:虽然我更喜欢使用(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);
}

答案 1 :(得分:1)

默认情况下,STL不需要使用malloc,但您可以传入allocator来指定它。请参阅Dr. Dobbs的this example

答案 2 :(得分:0)

我的系统上没有malloc_stats函数,但你可以通过创建一个1000000 int s的向量来运行一个简单的测试(只是为了防止你意外地保存你的所有工作)耗尽所有RAM并使系统崩溃:-))。

请注意,在许多操作系统上,malloc不是为程序分配内存的唯一方法。例如,在Linux上,您(或C ++实现)可以跳过malloc()并使用较低级别的系统函数,如mmap()sbrk()。因此,malloc_stats可能不会告诉您程序正在使用的所有内存。请查看getrusage

答案 3 :(得分:0)

您不能总是假设默认分配器和operator new使用malloc,但很可能所有来自同一个池。您询问特定于Linux的函数这一事实使其成为这种特定上下文的安全假设。

其他人建议您定义自定义分配器类。只有在每个STL容器声明中将该分配器作为模板参数传递时,这才有效。这是相当容易出错的,因此我不建议将其作为一种简单的分析策略。

至于第二个问题,不,除了STL容器之外的其他东西将分配内存。例如,fstream以实现定义的方式创建I / O缓冲区。 algorithm创建temporary_buffer个对象中的一些函数,它们不使用分配器。 (temporary_buffer不是标准的一部分;它是原始HP / SGI STL的一部分。其他实现可能称之为其他实现,但在任何情况下都允许某些函数分配临时工作空间。)