memory_manager.cxx

00001 #include <memory_manager.hpp>
00002 #include <gc++.hpp>
00003 #include <common.hpp>
00004 #include <VERSION>
00005 #include <algorithm>
00006 #include <cassert>
00007 #include <cstdlib>
00008 #include <numeric>
00009 #include <detail/gc++.hpp>
00010 #include <boost/bind.hpp>
00011 
00012 using namespace GCpp;
00013 using namespace std;
00014 
00015 namespace
00016 {
00017 
00018 GCPP_MUTEX global_gc_mutex;
00019 
00020 struct BlockHeader
00021 {
00022     MemoryAllocatorBase* allocator;
00023     BlockHeader* next;
00024     bool mark;
00025     
00026     BlockHeader (MemoryAllocatorBase* p_allocator)
00027     : allocator (p_allocator),
00028       mark (true)
00029     {}
00030 };
00031 
00032 inline
00033 BlockHeader* EXTRACT_HEADER (void* p_data)
00034 {
00035     return reinterpret_cast<BlockHeader*> (static_cast<Byte*> (p_data) - sizeof (BlockHeader));
00036 }
00037 
00038 inline
00039 void* OBJECT (void* p_data)
00040 {
00041     return static_cast<Byte*>(p_data) + sizeof (BlockHeader);
00042 }
00043 
00044 inline
00045 GCBasePointer* CALC_POINTER (void* p_data, size_t p_offset)
00046 {
00047     return reinterpret_cast<GCBasePointer*> (static_cast<Byte*> (p_data) + p_offset);
00048 }
00049 
00050 typedef size_t (MemoryAllocatorBase::*SumMember) ();
00051 
00052 struct Sum : binary_function<size_t, MemoryAllocatorBase*, size_t>
00053 {
00054     SumMember f_sum;
00055     
00056     Sum (SumMember p_sum)
00057     : f_sum (p_sum)
00058     {}
00059     
00060     size_t operator() (size_t p_value, MemoryAllocatorBase* p_item)
00061     {
00062         return p_value + (p_item->*f_sum) ();
00063     }
00064 };
00065 
00066 const Byte analyzed_tag = 0x01;
00067 const Byte assured_tag = 0x02;
00068 
00069 } // anonymous namespace
00070 
00071 MemoryAllocatorBase::MemoryAllocatorBase (size_t p_block_size)
00072 : FixedSizeAllocator (p_block_size + sizeof (BlockHeader)),
00073   f_status (0),
00074   f_destroyed (0),
00075   f_allocated (0),
00076   f_blocks (0)
00077 {
00078     GC::f_allocators.push_back (this);
00079 }
00080 
00081 MemoryAllocatorBase::~MemoryAllocatorBase ()
00082 {
00083     GC::f_allocators.remove (this);
00084 }
00085 
00086 void MemoryAllocatorBase::analyze (void* p_block)
00087 {
00088     Byte* org (static_cast<Byte*> (p_block));
00089     Byte* ptr (org);
00090     int lmt (block_size () - sizeof (void*) - sizeof (BlockHeader));
00091     
00092     while (ptr - org < lmt)
00093     {
00094         if (GCPointerManager::is_pointer (ptr))
00095         {
00096             f_offsets.push_back (ptr - org);
00097             ptr += sizeof (void*);
00098         }
00099         else
00100             ++ptr;
00101     }
00102     
00103     f_status |= analyzed_tag;
00104 }
00105 
00106 void MemoryAllocatorBase::mark_contained_pointers (void* p_block)
00107 {
00108     if (f_status % 2 == 0)
00109         analyze (p_block);
00110     
00111     vector<size_t>::iterator itr (f_offsets.begin ());
00112     vector<size_t>::iterator end (f_offsets.end ());
00113     
00114     vector<size_t> err;
00115     
00116     for (; itr != end; ++itr)
00117     {
00118         GCBasePointer* ptr (CALC_POINTER (p_block, *itr));
00119         
00120         // if we have completed at least one complete cycle, we do not validate the
00121         // pointers any more, because we have done it several times now and are
00122         // reasonable sure, that the pointers calculated from the f_offsets array are valid
00123         if (f_status & assured_tag or GCPointerManager::is_pointer (ptr))
00124             static_cast<GCBasePointer*> (ptr)->mark ();
00125         else
00126             err.push_back (*itr);
00127     }
00128     
00129     if (not err.empty ())
00130     {
00131         vector<size_t>::iterator rtr (err.begin ());
00132         vector<size_t>::iterator rnd (err.end ());
00133     
00134         for (; rtr != rnd; ++rtr)
00135             f_offsets.erase (remove (f_offsets.begin (), f_offsets.end (), *rtr), f_offsets.end ());
00136     }
00137 }
00138 
00139 void MemoryAllocatorBase::sweep ()
00140 {
00141     BlockHeader* hdr (static_cast<BlockHeader*>(f_blocks));
00142     f_blocks = 0;
00143     size_t dst (0);
00144     
00145     while (hdr)
00146     {
00147         assert (hdr->allocator == this);
00148         BlockHeader* del (hdr);
00149         
00150         if (not hdr->mark)
00151         {
00152             hdr = hdr->next;
00153             f_destroy_item (OBJECT (del));
00154             del->allocator = 0;
00155             free (del);
00156             ++dst;
00157         }
00158         else
00159         {
00160             hdr->mark = false;
00161             hdr = hdr->next;
00162             del->next = static_cast<BlockHeader*>(f_blocks);
00163             f_blocks = del;
00164         }
00165     }
00166     
00167     f_destroyed += dst;
00168     f_status |= assured_tag;
00169 }
00170 
00171 void MemoryAllocatorBase::unmark ()
00172 {
00173     BlockHeader* hdr (static_cast<BlockHeader*>(f_blocks));
00174     
00175     while (hdr)
00176     {
00177         assert (hdr->allocator == this);
00178         hdr->mark = false;
00179         hdr = hdr->next;
00180     }
00181 }
00182 
00183 void* MemoryAllocatorBase::malloc ()
00184 {
00185     GCPP_LOCK mlc (global_gc_mutex);
00186     
00187     Byte* dat (GC::stopped () ? static_cast<Byte*> (FixedSizeAllocator::malloc ()) : static_cast<Byte*> (internal_malloc ()));
00188     
00189     if (dat == 0)
00190     {
00191         size_t old (f_destroyed);
00192         
00193         GC::internal_collect ();
00194         
00195         if (old != f_destroyed)
00196             dat = static_cast<Byte*> (internal_malloc ());
00197         else
00198         {
00199             dat = static_cast<Byte*> (internal_add_block ());
00200             GC::f_threshold += GC::f_threshold / 4;
00201         }
00202     }
00203     
00204     BlockHeader* blk (new (dat) BlockHeader (this));
00205     blk->next = static_cast<BlockHeader*> (f_blocks);
00206     f_blocks = blk;
00207     
00208     ++f_allocated;
00209     
00210     return OBJECT (dat);
00211 }
00212 
00213 void* MemoryAllocatorBase::confirm (void* p_storage)
00214 {
00215     BlockHeader* hdr (EXTRACT_HEADER (p_storage));
00216     
00217     if (hdr->allocator == this)
00218         return p_storage;
00219     
00220     return 0;
00221 }
00222 
00223 bool GC::f_stop (false);
00224 size_t GC::f_allocated (0);
00225 size_t GC::f_threshold (50000000);
00226 IntrusiveList<MemoryAllocatorBase> GC::f_allocators;
00227 
00228 void GC::start ()
00229 {
00230     f_stop = false;
00231 }
00232 
00233 void GC::stop ()
00234 {
00235     f_stop = true;
00236 }
00237 
00238 void GC::mark (void* p_block)
00239 {
00240     if (not static_cast<GCBasePointer*> (p_block)->is_contained ())
00241         static_cast<GCBasePointer*> (p_block)->mark ();
00242 }
00243 
00244 void GC::mark_recursively (void* p_pointer)
00245 {
00246     GCBasePointer* ptr (static_cast<GCBasePointer*> (p_pointer));
00247     
00248     if (ptr->storage ())
00249     {
00250         BlockHeader* hdr (EXTRACT_HEADER (ptr->storage ()));
00251             
00252         // we were already here, return to avoid endless recursion
00253         if (hdr->mark)
00254             return;
00255                 
00256         hdr->mark = true;
00257         hdr->allocator->mark_contained_pointers (ptr->storage ());
00258     }
00259 }
00260 
00261 void GC::internal_collect ()
00262 {
00263     if (f_allocated < f_threshold)
00264         return;
00265     
00266     if (not f_stop)
00267     {
00268         for_each (GCPointerManager::begin (), GCPointerManager::end (), mark);
00269         for_each (f_allocators.begin (), f_allocators.end (), boost::bind (&MemoryAllocatorBase::sweep, _1));
00270     }
00271 }
00272 
00273 void GC::collect ()
00274 {
00275     GCPP_LOCK lck (global_gc_mutex);
00276     
00277     bool old (f_stop);
00278     f_stop = false;
00279     size_t alc (f_allocated);
00280     f_allocated = f_threshold;
00281 
00282     for_each (f_allocators.begin (), f_allocators.end (), boost::bind (&MemoryAllocatorBase::unmark, _1));
00283     internal_collect ();
00284     
00285     f_stop = old;
00286     f_allocated = alc;
00287 }
00288 
00289 bool GC::stopped ()
00290 {
00291     return f_stop;
00292 }
00293 
00294 size_t GC::destroyed ()
00295 {
00296     Sum sum (&MemoryAllocatorBase::destroyed);
00297     return accumulate (f_allocators.begin (), f_allocators.end (), 0, sum);
00298 }
00299 
00300 size_t GC::allocated ()
00301 {
00302     Sum sum (&MemoryAllocatorBase::allocated);
00303     return accumulate (f_allocators.begin (), f_allocators.end (), 0, sum);
00304 }
00305 
00306 string GC::version ()
00307 {
00308     return string (VERSION_STRING);
00309 }
00310 
00311 size_t GC::in_use ()
00312 {
00313     return f_allocated;
00314 }
00315         
00316 size_t GC::threshold ()
00317 {
00318     return f_threshold;
00319 }
00320         
00321 void GC::compact (bool p_new_limit)
00322 {
00323     GCPP_LOCK lck (global_gc_mutex);
00324     for_each (f_allocators.begin (), f_allocators.end (), boost::bind (&MemoryAllocatorBase::compact, _1));
00325     
00326     if (p_new_limit)
00327         f_threshold = max (f_allocated, static_cast<size_t> (50000000));
00328 }
00329 
00330 void GC::finalize ()
00331 {
00332     size_t old;
00333     
00334     do
00335     {
00336         old = GC::destroyed ();
00337         GC::collect ();
00338     } while (GC::destroyed () > old);
00339 }
00340 
00341 Byte* GCpp::OS_malloc (size_t p_size)
00342 {
00343     Byte* ret (static_cast<Byte*> (::malloc (p_size + sizeof (size_t))));
00344     *reinterpret_cast<size_t*> (ret) = p_size;
00345     GC::f_allocated += p_size;
00346     return ret + sizeof (size_t);
00347 }
00348 
00349 void GCpp::OS_free (Byte* p_block)
00350 {
00351     Byte* blk (p_block - sizeof (size_t));
00352     GC::f_allocated-= *reinterpret_cast<size_t*> (blk);
00353     ::free (blk);
00354 }

Generated on Thu Dec 27 14:01:59 2007 for GC++ by  doxygen 1.5.4