• Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • Examples
  • File List
  • File Members

GC.h

Go to the documentation of this file.
00001 // GC.h: Garbage Collector for Gnash
00002 // 
00003 //   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
00004 //   Foundation, Inc
00005 // 
00006 // This program is free software; you can redistribute it and/or modify
00007 // it under the terms of the GNU General Public License as published by
00008 // the Free Software Foundation; either version 3 of the License, or
00009 // (at your option) any later version.
00010 // 
00011 // This program is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 // GNU General Public License for more details.
00015 // 
00016 // You should have received a copy of the GNU General Public License
00017 // along with this program; if not, write to the Free Software
00018 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019 
00020 #ifndef GNASH_GC_H
00021 #define GNASH_GC_H
00022 
00023 #include <list>
00024 #include <map>
00025 #include <string>
00026 
00027 #ifndef NDEBUG
00028 # include <boost/thread.hpp>
00029 #endif
00030 
00031 #include "dsodefs.h"
00032 
00033 // Define the following macro to enable GC verbosity 
00034 // Verbosity levels:
00035 //   1 - print stats about how many resources are registered and how many 
00036 //       are deleted, everytime the GC collector runs.
00037 //   2 - print a message for every GcResource being registered and being deleted
00038 //   3 - print info about the mark scan 
00039 //   
00040 //#define GNASH_GC_DEBUG 1
00041 
00042 #ifdef GNASH_GC_DEBUG
00043 # include "log.h"
00044 # include "utility.h"
00045 # include <typeinfo>
00046 #endif
00047 
00048 #include <cassert>
00049 
00050 
00051 namespace gnash {
00052 
00053 class GC;
00054 
00056 //
00062 class GcRoot
00063 {
00064 
00065 public:
00066 
00068     //
00075     virtual void markReachableResources() const=0;
00076 
00077     virtual ~GcRoot() {}
00078 };
00079 
00081 //
00084 class GcResource
00085 {
00086 
00087 public:
00088 
00089     friend class GC;
00090 
00092     //
00096     GcResource();
00097 
00101     //
00105     void setReachable() const
00106     {
00107 
00108         if ( _reachable )
00109         {
00110 #if GNASH_GC_DEBUG > 2
00111             log_debug(_("Instance %p of class %s already reachable, setReachable doing nothing"),
00112                     (void*)this, typeName(*this));
00113 #endif
00114             return;
00115         }
00116 
00117 #if GNASH_GC_DEBUG  > 2
00118         log_debug(_("Instance %p of class %s set to reachable, scanning reachable resources from it"),
00119                 (void*)this, typeid(*this).name());
00120 #endif
00121 
00122         _reachable = true;
00123         markReachableResources();
00124     }
00125 
00127     bool isReachable() const { return _reachable; }
00128 
00130     void clearReachable() const { _reachable = false; }
00131 
00132 protected:
00133 
00135     //
00148     virtual void markReachableResources() const
00149     {
00150         assert(_reachable);
00151 #if GNASH_GC_DEBUG > 1
00152         log_debug(_("Class %s didn't override the markReachableResources() method"), typeid(*this).name());
00153 #endif
00154     }
00155 
00157     //
00161     virtual ~GcResource()
00162     {
00163     }
00164 
00165 private:
00166 
00167     mutable bool _reachable;
00168 
00169 };
00170 
00172 //
00185 class DSOEXPORT GC
00186 {
00187 
00188 public:
00189 
00191     //
00192     static GC& init(GcRoot& r);
00193 
00196     //
00199     static void cleanup();
00200 
00202     //
00206     static GC& get() {
00207         return *_singleton;
00208     }
00209 
00211     //
00227     void addCollectable(const GcResource* item)
00228     {
00229 #ifndef NDEBUG
00230         boost::thread self;
00231         assert(self == mainThread);
00232         assert(item);
00233         assert(! item->isReachable());
00234         // The following assertion is expensive ...
00235         //assert(std::find(_resList.begin(), _resList.end(), item) == _resList.end());
00236 #endif
00237 
00238         _resList.push_back(item); ++_resListSize;
00239 #if GNASH_GC_DEBUG > 1
00240         log_debug(_("GC: collectable %p added, num collectables: %d"), item, _resListSize);
00241 #endif
00242     }
00243 
00245     void fuzzyCollect()
00246     {
00247         // Heuristic to decide wheter or not to run the collection cycle
00248         //
00249         //
00250         // Things to consider:
00251         //
00252         //  - Cost 
00253         //      - Depends on the number of reachable collectables
00254         //      - Depends on the frequency of runs
00255         //
00256         //  - Advantages 
00257         //      - Depends on the number of unreachable collectables
00258         //
00259         //  - Cheaply computable informations
00260         //      - Number of collectables (currently O(n) but can be optimized)
00261         //      - Total heap-allocated memory (currently unavailable)
00262         //
00263         // Current heuristic:
00264         //
00265         //  - We run the cycle again if X new collectables were allocated
00266         //    since last cycle run. X defaults to maxNewCollectablesCount
00267         //    and can be changed by user (GNASH_GC_TRIGGER_THRESHOLD env
00268         //    variable).
00269         //
00270         // Possible improvements:
00271         //
00272         //  - Adapt X (maxNewCollectablesCount) based on cost/advantage
00273         //    runtime analisys
00274         //
00275 
00276         if ( _resListSize <  _lastResCount + maxNewCollectablesCount )
00277         {
00278 #if GNASH_GC_DEBUG  > 1
00279             log_debug(_("GC: collection cycle skipped - %d/%d new resources allocated since last run (from %d to %d)"), _resListSize-_lastResCount, maxNewCollectablesCount, _lastResCount, _resListSize);
00280 #endif // GNASH_GC_DEBUG
00281             return;
00282         }
00283 
00284         runCycle();
00285     }
00286 
00288     //
00291     void runCycle();
00292 
00293     typedef std::map<std::string, unsigned int> CollectablesCount;
00294 
00296     void countCollectables(CollectablesCount& count) const;
00297 
00298 private:
00299 
00302     static unsigned int maxNewCollectablesCount;
00303 
00305     GC(GcRoot& root)
00306         :
00307         _resListSize(0),
00308         _root(root),
00309         _lastResCount(0)
00310 #ifdef GNASH_GC_DEBUG 
00311         , _collectorRuns(0)
00312 #endif
00313     {
00314 #ifdef GNASH_GC_DEBUG 
00315         log_debug(_("GC %p created"), (void*)this);
00316 #endif
00317     }
00318 
00320     ~GC();
00321 
00323     typedef std::list<const GcResource *> ResList;
00324 
00326     void markReachable()
00327     {
00328 #if GNASH_GC_DEBUG > 2
00329         log_debug(_("GC %p: MARK SCAN"), (void*)this);
00330 #endif
00331         _root.markReachableResources();
00332     }
00333 
00335     //
00338     size_t cleanUnreachable();
00339 
00341     ResList _resList;
00342 
00343     // Size of the list above, to avoid the
00344     // cost of computing it  ..
00345     // .. this is O(n) on GNU stdc++ lib !
00346     //
00347     ResList::size_type _resListSize;
00348 
00349     GcRoot& _root;
00350 
00351     static GC* _singleton;
00352 
00353 #ifndef NDEBUG
00354 
00355 
00356 
00357     boost::thread mainThread;
00358 #endif
00359 
00362     ResList::size_type _lastResCount;
00363 
00364 #ifdef GNASH_GC_DEBUG 
00365 
00366     size_t _collectorRuns;
00367 #endif
00368 };
00369 
00370 
00371 inline GcResource::GcResource()
00372     :
00373     _reachable(false)
00374 {
00375     GC::get().addCollectable(this);
00376 }
00377 
00378 } // namespace gnash
00379 
00380 #endif // GNASH_GC_H

Generated on Thu Sep 30 2010 14:34:58 for Gnash by  doxygen 1.7.1