Gnash
0.8.10
|
00001 // GC.h: Garbage Collector for Gnash 00002 // 00003 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 00004 // Free Software 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 // Define the following macro to enable GC verbosity 00024 // Verbosity levels: 00025 // 1 - print stats about how many resources are registered and how many 00026 // are deleted, everytime the GC collector runs. 00027 // 2 - print a message for every GcResource being registered and being deleted 00028 // 3 - print info about the mark scan 00029 // 00030 //#define GNASH_GC_DEBUG 1 00031 00032 #include <list> 00033 #include <map> 00034 #include <string> 00035 #include <cassert> 00036 00037 #include "dsodefs.h" 00038 #ifdef GNASH_GC_DEBUG 00039 # include "log.h" 00040 # include "utility.h" 00041 #endif 00042 00043 // Forward declarations. 00044 namespace gnash { 00045 class GC; 00046 } 00047 00048 namespace gnash { 00049 00051 // 00055 class GcRoot 00056 { 00057 public: 00058 00060 // 00066 virtual void markReachableResources() const = 0; 00067 00068 virtual ~GcRoot() {} 00069 }; 00070 00072 // 00074 class GcResource 00075 { 00076 public: 00077 00078 friend class GC; 00079 00081 // 00083 GcResource(GC& gc); 00084 00086 // 00089 // 00092 void setReachable() const { 00093 00094 if (_reachable) { 00095 00096 #if GNASH_GC_DEBUG > 2 00097 log_debug(_("Instance %p of class %s already reachable, " 00098 "setReachable doing nothing"), (void*)this, 00099 typeName(*this)); 00100 #endif 00101 return; 00102 } 00103 00104 #if GNASH_GC_DEBUG > 2 00105 log_debug(_("Instance %p of class %s set to reachable, scanning " 00106 "reachable resources from it"), (void*)this, 00107 typeName(*this)); 00108 #endif 00109 00110 _reachable = true; 00111 markReachableResources(); 00112 } 00113 00115 bool isReachable() const { return _reachable; } 00116 00118 void clearReachable() const { _reachable = false; } 00119 00120 protected: 00121 00123 // 00136 virtual void markReachableResources() const { 00137 assert(_reachable); 00138 #if GNASH_GC_DEBUG > 1 00139 log_debug(_("Class %s didn't override the markReachableResources() " 00140 "method"), typeName(*this)); 00141 #endif 00142 } 00143 00145 // 00149 virtual ~GcResource() {} 00150 00151 private: 00152 00153 mutable bool _reachable; 00154 00155 }; 00156 00158 // 00164 class DSOEXPORT GC 00165 { 00166 00167 public: 00168 00170 // 00173 GC(GcRoot& root); 00174 00176 ~GC(); 00177 00179 // 00194 void addCollectable(const GcResource* item) { 00195 00196 #ifndef NDEBUG 00197 assert(item); 00198 assert(!item->isReachable()); 00199 #endif 00200 00201 _resList.push_back(item); ++_resListSize; 00202 00203 #if GNASH_GC_DEBUG > 1 00204 log_debug(_("GC: collectable %p added, num collectables: %d"), item, 00205 _resListSize); 00206 #endif 00207 } 00208 00210 void fuzzyCollect() { 00211 00212 // Heuristic to decide wheter or not to run the collection cycle 00213 // 00214 // 00215 // Things to consider: 00216 // 00217 // - Cost 00218 // - Depends on the number of reachable collectables 00219 // - Depends on the frequency of runs 00220 // 00221 // - Advantages 00222 // - Depends on the number of unreachable collectables 00223 // 00224 // - Cheaply computable informations 00225 // - Number of collectables (currently O(n) but can be optimized) 00226 // - Total heap-allocated memory (currently unavailable) 00227 // 00228 // Current heuristic: 00229 // 00230 // - We run the cycle again if X new collectables were allocated 00231 // since last cycle run. X defaults to maxNewCollectablesCount 00232 // and can be changed by user (GNASH_GC_TRIGGER_THRESHOLD env 00233 // variable). 00234 // 00235 // Possible improvements: 00236 // 00237 // - Adapt X (maxNewCollectablesCount) based on cost/advantage 00238 // runtime analisys 00239 // 00240 00241 if (_resListSize < _lastResCount + _maxNewCollectablesCount) { 00242 #if GNASH_GC_DEBUG > 1 00243 log_debug(_("GC: collection cycle skipped - %d/%d new resources " 00244 "allocated since last run (from %d to %d)"), 00245 _resListSize-_lastResCount, _maxNewCollectablesCount, 00246 _lastResCount, _resListSize); 00247 #endif // GNASH_GC_DEBUG 00248 return; 00249 } 00250 00251 runCycle(); 00252 } 00253 00255 // 00258 void runCycle(); 00259 00260 typedef std::map<std::string, unsigned int> CollectablesCount; 00261 00263 void countCollectables(CollectablesCount& count) const; 00264 00265 private: 00266 00268 typedef std::list<const GcResource*> ResList; 00269 00271 void markReachable() { 00272 #if GNASH_GC_DEBUG > 2 00273 log_debug(_("GC %p: MARK SCAN"), (void*)this); 00274 #endif 00275 _root.markReachableResources(); 00276 } 00277 00279 // 00281 size_t cleanUnreachable(); 00282 00285 size_t _maxNewCollectablesCount; 00286 00288 ResList _resList; 00289 00291 ResList::size_type _resListSize; 00292 00294 GcRoot& _root; 00295 00298 ResList::size_type _lastResCount; 00299 00300 #ifdef GNASH_GC_DEBUG 00301 00302 size_t _collectorRuns; 00303 #endif 00304 }; 00305 00306 00307 inline GcResource::GcResource(GC& gc) 00308 : 00309 _reachable(false) 00310 { 00311 gc.addCollectable(this); 00312 } 00313 00314 } // namespace gnash 00315 00316 #endif // GNASH_GC_H