diff --git a/include/boost/detail/quick_allocator.hpp b/include/boost/detail/quick_allocator.hpp index 66ba3d8..2d8d735 100644 --- a/include/boost/detail/quick_allocator.hpp +++ b/include/boost/detail/quick_allocator.hpp @@ -23,7 +23,6 @@ #include #include -#include #include // ::operator new, ::operator delete #include // std::size_t @@ -45,10 +44,27 @@ template struct allocator_impl { typedef freeblock block; + // It may seem odd to use such small pages. + // + // However, on a typical Windows implementation that uses + // the OS allocator, "normal size" pages interact with the + // "ordinary" operator new, slowing it down dramatically. + // + // 512 byte pages are handled by the small object allocator, + // and don't interfere with ::new. + // + // The other alternative is to use much bigger pages (1M.) + + enum { items_per_page = 496 / size }; // 1048560 / size + +#ifdef BOOST_HAS_THREADS static lightweight_mutex mutex; - static std::deque store; +#endif + static block * free; - + static block * page; + static unsigned last; + static inline void * alloc() { #ifdef BOOST_HAS_THREADS @@ -61,8 +77,15 @@ template struct allocator_impl } else { - store.resize(store.size() + 1); - return &store.back(); + if(last == items_per_page) + { + // "Listen to me carefully: there is no memory leak" + // -- Scott Meyers, Eff C++ 2nd Ed Item 10 + page = ::new block[items_per_page]; + last = 0; + } + + return &page[last++]; } } @@ -84,8 +107,13 @@ template struct allocator_impl } else { - store.resize(store.size() + 1); - return &store.back(); + if(last == items_per_page) + { + page = ::new block[items_per_page]; + last = 0; + } + + return &page[last++]; } } } @@ -105,34 +133,36 @@ template struct allocator_impl static inline void dealloc(void * pv, std::size_t n) { - if(pv != 0) // 18.4.1.1/13 + if(n != size) // class-specific delete called for a derived object + { + ::operator delete(pv); + } + else if(pv != 0) // 18.4.1.1/13 { - if(n != size) // class-specific delete called for a derived object - { - ::operator delete(pv); - } - else - { #ifdef BOOST_HAS_THREADS - lightweight_mutex::scoped_lock lock(mutex); + lightweight_mutex::scoped_lock lock(mutex); #endif - block * pb = static_cast(pv); - pb->next = free; - free = pb; - } + block * pb = static_cast(pv); + pb->next = free; + free = pb; } } }; +#ifdef BOOST_HAS_THREADS template lightweight_mutex allocator_impl::mutex; - -template - std::deque< freeblock > allocator_impl::store; +#endif template freeblock * allocator_impl::free = 0; +template + freeblock * allocator_impl::page = 0; + +template + unsigned allocator_impl::last = allocator_impl::items_per_page; + template struct quick_allocator: public allocator_impl< sizeof(T), boost::alignment_of::value > {