简体   繁体   English

STL C ++对象的内存分配

[英]Memory Allocation by STL C++ Objects

I am using malloc_stats() function to display the amount of "system bytes" and "in use" bytes used by the process. 我使用malloc_stats()函数来显示进程使用的“系统字节”和“使用中”字节的数量。 I wanted to know if the in use bytes also include the memory used by STL C++ Objects like map, vector, sets? 我想知道使用中的字节是否还包括STL C ++对象使用的内存,如map,vector,sets?

If yes, is it safe to assume that this is only amount of memory that will be used by the process? 如果是,是否可以安全地假设这只是进程将使用的内存量?

That is not specified in the standard, new may call malloc or not. 这没有在标准中指定,new可能会调用malloc。 In practice in the implementations I have worked with, it does. 在我使用过的实现中,确实如此。

The best way to do what you want is to define your own new operator that accounts for allocated memory, or use an accounting allocator for STL containers like this one: 做你想做的事情的最好方法是定义你自己的新运算符来计算分配的内存,或者像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 ***********/

An example of accounting with new: Although I'd prefer using (3) malloc_hook and an unordered_map 使用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);
}

The STL is not required to use malloc by default, but you can pass in an allocator to specify this. 默认情况下,STL不需要使用malloc,但您可以传入一个分配器来指定它。 See this example at Dr. Dobbs. 请参阅Dobbs博士的这个例子

I don't have a malloc_stats function on my system, but you could run a simple test by creating a vector of 1000000 int s or something (just be sure you save all your work just in case you accidentally use up all your RAM and crash your system :-) ). 我的系统上没有malloc_stats函数,但你可以通过创建一个1000000 int s的向量来运行一个简单的测试(只是确保你保存所有的工作,以防万一你不小心耗尽所有的RAM并崩溃你的系统 :-) )。

Note that on many OSes, malloc is not the only way to allocate memory to a program. 请注意,在许多操作系统上, malloc不是为程序分配内存的唯一方法。 On Linux, for instance, you (or a C++ implementation) can skip malloc() and use lower-level system functions like mmap() and sbrk() . 例如,在Linux上,您(或C ++实现)可以跳过malloc()并使用较低级别的系统函数,如mmap()sbrk() Thus, malloc_stats might not tell you all of the memory a program is using. 因此, malloc_stats可能不会告诉您程序正在使用的所有内存。 Check out getrusage for that. 检查getrusage为此。

You can't always assume that the default allocator and operator new use malloc , but it's pretty likely that all come from the same pool. 你不能总是假设默认的分配器和operator new使用malloc ,但很可能所有都来自同一个池。 The fact that you're asking about a Linux-specific function makes it a safe assumption for this particular context. 您询问特定于Linux的函数这一事实使其成为这一特定上下文的安全假设。

Others have suggested that you define a custom allocator class. 其他人建议您定义自定义分配器类。 That will only work if you pass that allocator as a template parameter in every STL container declaration you have. 只有在每个STL容器声明中将该分配器作为模板参数传递时,这才有效。 That is fairly error-prone, so I wouldn't recommend it as an easy analysis strategy. 这是相当容易出错的,因此我不建议将其作为简单的分析策略。

As for the second question, no, other things besides STL containers will allocate memory. 至于第二个问题,不,除了STL容器之外的其他东西将分配内存。 For example, fstream creates an I/O buffer in an implementation-defined way. 例如, fstream以实现定义的方式创建I / O缓冲区。 Some functions in algorithm create temporary_buffer objects, which does not use an allocator. algorithm某些函数会创建temporary_buffer对象,而不使用分配器。 ( temporary_buffer is not part of the standard; it is part of the original HP/SGI STL though. Other implementations may call it something else, but in any case some functions are allowed to allocate temporary workspace.) temporary_buffer不是标准的一部分;它是原始HP / SGI STL的一部分。其他实现可能称之为其他实现,但在任何情况下都允许某些函数分配临时工作空间。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM