简体   繁体   中英

Preventing memory freeing in STL Container

I have an STL container (std::list) that I am constantly reusing. By this I mean I

  1. push a number of elements into the container
  2. remove the elements during processing
  3. clear the container
  4. rinse and repeat a large number of times

When profiling using callgrind I am seeing a large number of calls to new ( malloc ) and delete ( free ) which can be quite expensive. I am therefore looking for some way to preferably preallocate a reasonably large number of elements. I would also like my allocation pool to continue to increase until a high water mark is reach and for the allocation pool to continue to hang onto the memory until the container itself is deleted.

Unfortunately the standard allocator continually resizes the memory pool so I am looking for some allocator that will do the above without me having to write my own.

Does such an allocator exist and where can I find such an allocator?

I am working on both Linux using GCC and Android using the STLPort.

Edit : Placement new is ok, what I want to minimize is heap walking which is expensive. I would also like all my object to be as close to eachother as possible to minimize cache misses.

It sounds like you may be just using the wrong kind of container: With a list, each element occupies a separate chunk of memory, to allow individual inserts/deletes - so every addition/deletion form the list will require a separate new()/delete() .

If you can use a std::vector instead, then you can reserve the required size before adding the items.

Also for deletion, it's usually best not to remove the items individually. Just call clear() on the container to empty. it.


Edit: You've now made it clear in the comments that your ' remove the elements during processing ' step is removing elements from the middle of the list and must not invalidate iterators, so switching to a vector is not suitable. I'll leave this answer for now (for the sake of the comment thread!)

The allocator boost::fast_pool_allocator is designed for use with std::list .

The documentation claims that "If you are seriously concerned about performance, use boost::fast_pool_allocator when dealing with containers such as std::list , and use boost::pool_allocator when dealing with containers such as std::vector ."

Note that boost::fast_pool_allocator is a singleton and by default it never frees allocated memory. However, it is implemented using boost::singleton_pool and you can make it free memory by calling the static functions boost::singleton_pool::release_memory() and boost::singleton_pool::purge_memory() .

You can try and benchmark your app with http://goog-perftools.sourceforge.net/doc/tcmalloc.html , I've seen some good improvements in some of my projects (no numbers at hand though, sorry)

EDIT : Seems the code/download has been moved there: http://code.google.com/p/gperftools/?redir=1

Comment was too short so I will post my thoughts as an answer.

IMO, new/delete can come only from two places in this context.

I believe std::list<T> is implemented with some kind of nodes as normally lists are, for various reasons. Therefore, each insertion and removal of an element will have to result in new/delete of a node. Moreover, if the object of type T has any allocations and deallocations in c'tor/d'tor, they will be called as well.

You can avoid recreation of standard stuff by reiterating over existing nodes instead of deleting them. You can use std::vector and std::vector::reserve or std::array if you want to squeeze it to c-level.

Nonetheless, for every object created there must be called a destructor. The only way I see to avoid creations and destructions is to use T::operator= when reiterating over container, or maybe some c++13 move stuff if its suitable in your case.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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