├── .gitignore ├── README ├── gc.cpp ├── gc.h └── makefile /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.o 3 | *.a 4 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | C++ Garbage Collection Library 2 | ============================== 3 | 4 | This is a library to manage memory in C++ programs using a garbage 5 | collector. It uses a mark and sweep algorithm. 6 | 7 | All objects that are to be managed by the collector should be derived 8 | from GCObject: 9 | 10 | class Test : public GCObject { 11 | ... 12 | }; 13 | 14 | If the object maintains references to other GC managed objects it 15 | should override 'markChildren' to call 'mark' on those objects: 16 | 17 | class Test2 : public GCObject { 18 | private: 19 | Test* mTest; 20 | 21 | public: 22 | virtual void markChildren() { 23 | mTest->mark(); 24 | } 25 | ... 26 | }; 27 | 28 | Periodic calls to GarbageCollector::GC.collect() should be made to 29 | delete unreferenced objects and free memory. This call will call 30 | 'mark' on all the root objects, ensuring that they and their children 31 | are not deleted, and and remaining objects are destroyed. 32 | 33 | To add an object as a root, call GarbageCollector::GC.addRoot(). 34 | 35 | License 36 | ======= 37 | Redistribution and use in source and binary forms, with or without 38 | modification, are permitted provided that the following conditions are met: 39 | 40 | 1. Redistributions of source code must retain the above copyright notice, 41 | this list of conditions and the following disclaimer. 42 | 43 | 2. Redistributions in binary form must reproduce the above copyright notice, 44 | this list of conditions and the following disclaimer in the documentation 45 | and/or other materials provided with the distribution. 46 | 47 | THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 48 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 49 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 50 | DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 51 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 52 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 53 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 54 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 55 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 56 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 57 | 58 | Feedback 59 | ======== 60 | I host this on githib: 61 | http://github.com/doublec/gc 62 | 63 | Feel free to clone, hack away, suggest patches, etc. I can be reached 64 | via email: chris.double@double.co.nz 65 | -------------------------------------------------------------------------------- /gc.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2009 Chris Double. All Rights Reserved. 2 | // See the license at the end of this file 3 | #include 4 | #include 5 | #include "gc.h" 6 | 7 | using namespace std; 8 | 9 | // GCObject 10 | GCObject::GCObject() : 11 | mMarked(false) { 12 | GarbageCollector::GC.addObject(this); 13 | } 14 | 15 | GCObject::GCObject(GCObject const&) : 16 | mMarked(false) { 17 | GarbageCollector::GC.addObject(this); 18 | } 19 | 20 | GCObject::~GCObject() { 21 | } 22 | 23 | void GCObject::mark() { 24 | if (!mMarked) { 25 | mMarked = true; 26 | markChildren(); 27 | } 28 | } 29 | 30 | void GCObject::markChildren() { 31 | } 32 | 33 | // GCMemory 34 | GCMemory::GCMemory(int size) : mSize(size) { 35 | mMemory = new unsigned char[size]; 36 | } 37 | 38 | GCMemory::~GCMemory() { 39 | delete [] mMemory; 40 | } 41 | 42 | unsigned char* GCMemory::get() { 43 | return mMemory; 44 | } 45 | 46 | int GCMemory::size() { 47 | return mSize; 48 | } 49 | 50 | // GarbageCollector 51 | GarbageCollector GarbageCollector::GC; 52 | 53 | void GarbageCollector::collect(bool verbose) { 54 | using namespace boost::posix_time; 55 | unsigned int start = (microsec_clock::universal_time() - ptime(min_date_time)).total_milliseconds(); 56 | 57 | // Mark root objects 58 | for (ObjectSet::iterator it = mRoots.begin(); 59 | it != mRoots.end(); 60 | ++it) 61 | (*it)->mark(); 62 | 63 | // Mark pinned objects 64 | for (PinnedSet::iterator it = mPinned.begin(); 65 | it != mPinned.end(); 66 | ++it) 67 | (*it).first->mark(); 68 | 69 | if (verbose) { 70 | cout << "Roots: " << mRoots.size() << endl; 71 | cout << "Pinned: " << mPinned.size() << endl; 72 | cout << "GC: " << mHeap.size() << " objects in heap" << endl; 73 | } 74 | 75 | sweep(verbose); 76 | 77 | if (verbose) { 78 | unsigned int end = (microsec_clock::universal_time() - ptime(min_date_time)).total_milliseconds(); 79 | cout << "GC: " << (end-start) << " milliseconds" << endl; 80 | } 81 | } 82 | 83 | void GarbageCollector::addRoot(GCObject* root) { 84 | mRoots.insert(root); 85 | } 86 | 87 | void GarbageCollector::removeRoot(GCObject* root) { 88 | mRoots.erase(root); 89 | } 90 | 91 | void GarbageCollector::pin(GCObject* o) { 92 | PinnedSet::iterator it = mPinned.find(o); 93 | if (it == mPinned.end()) { 94 | mPinned.insert(make_pair(o, 1)); 95 | } 96 | else { 97 | (*it).second++; 98 | } 99 | } 100 | 101 | void GarbageCollector::unpin(GCObject* o) { 102 | PinnedSet::iterator it = mPinned.find(o); 103 | assert(it != mPinned.end()); 104 | 105 | if (--((*it).second) == 0) 106 | mPinned.erase(it); 107 | } 108 | 109 | void GarbageCollector::addObject(GCObject* o) { 110 | mHeap.insert(o); 111 | } 112 | 113 | void GarbageCollector::removeObject(GCObject* o) { 114 | mHeap.erase(o); 115 | } 116 | 117 | void GarbageCollector::sweep(bool verbose) { 118 | unsigned int live = 0; 119 | unsigned int dead = 0; 120 | unsigned int total = 0; 121 | vector erase; 122 | for (ObjectSet::iterator it = mHeap.begin(); 123 | it != mHeap.end(); 124 | ++it) { 125 | GCObject* p = *it; 126 | total++; 127 | if (p->mMarked) { 128 | p->mMarked = false; 129 | ++live; 130 | } 131 | else { 132 | erase.push_back(it); 133 | } 134 | } 135 | dead = erase.size(); 136 | for (vector::iterator it = erase.begin(); 137 | it != erase.end(); 138 | ++it) { 139 | GCObject* p = **it; 140 | mHeap.erase(*it); 141 | delete p; 142 | } 143 | if (verbose) { 144 | cout << "GC: " << live << " objects live after sweep" << endl; 145 | cout << "GC: " << dead << " objects dead after sweep" << endl; 146 | } 147 | } 148 | 149 | int GarbageCollector::live() { 150 | return mHeap.size(); 151 | } 152 | 153 | // Copyright (C) 2009 Chris Double. All Rights Reserved. 154 | // The original author of this code can be contacted at: chris.double@double.co.nz 155 | // 156 | // Redistribution and use in source and binary forms, with or without 157 | // modification, are permitted provided that the following conditions are met: 158 | // 159 | // 1. Redistributions of source code must retain the above copyright notice, 160 | // this list of conditions and the following disclaimer. 161 | // 162 | // 2. Redistributions in binary form must reproduce the above copyright notice, 163 | // this list of conditions and the following disclaimer in the documentation 164 | // and/or other materials provided with the distribution. 165 | // 166 | // THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 167 | // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 168 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 169 | // DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 170 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 171 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 172 | // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 173 | // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 174 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 175 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 176 | // 177 | -------------------------------------------------------------------------------- /gc.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2009 Chris Double. All Rights Reserved. 2 | // See the license at the end of this file 3 | #if !defined(GC_H) 4 | #define GC_H 5 | 6 | #include 7 | #include 8 | 9 | // Base class for all objects that are tracked by 10 | // the garbage collector. 11 | class GCObject { 12 | public: 13 | 14 | // For mark and sweep algorithm. When a GC occurs 15 | // all live objects are traversed and mMarked is 16 | // set to true. This is followed by the sweep phase 17 | // where all unmarked objects are deleted. 18 | bool mMarked; 19 | 20 | public: 21 | GCObject(); 22 | GCObject(GCObject const&); 23 | virtual ~GCObject(); 24 | 25 | // Mark the object and all its children as live 26 | void mark(); 27 | 28 | // Overridden by derived classes to call mark() 29 | // on objects referenced by this object. The default 30 | // implemention does nothing. 31 | virtual void markChildren(); 32 | }; 33 | 34 | // Wrapper for an array of bytes managed by the garbage 35 | // collector. 36 | class GCMemory : public GCObject { 37 | public: 38 | unsigned char* mMemory; 39 | int mSize; 40 | 41 | public: 42 | GCMemory(int size); 43 | virtual ~GCMemory(); 44 | 45 | unsigned char* get(); 46 | int size(); 47 | }; 48 | 49 | // Garbage Collector. Implements mark and sweep GC algorithm. 50 | class GarbageCollector { 51 | public: 52 | // A collection of all active heap objects. 53 | typedef std::set ObjectSet; 54 | ObjectSet mHeap; 55 | 56 | // Collection of objects that are scanned for garbage. 57 | ObjectSet mRoots; 58 | 59 | // Pinned objects 60 | typedef std::map PinnedSet; 61 | PinnedSet mPinned; 62 | 63 | // Global garbage collector object 64 | static GarbageCollector GC; 65 | 66 | public: 67 | // Perform garbage collection. If 'verbose' is true then 68 | // GC stats will be printed to stdout. 69 | void collect(bool verbose = false); 70 | 71 | // Add a root object to the collector. 72 | void addRoot(GCObject* root); 73 | 74 | // Remove a root object from the collector. 75 | void removeRoot(GCObject* root); 76 | 77 | // Pin an object so it temporarily won't be collected. 78 | // Pinned objects are reference counted. Pinning it 79 | // increments the count. Unpinning it decrements it. When 80 | // the count is zero then the object can be collected. 81 | void pin(GCObject* o); 82 | void unpin(GCObject* o); 83 | 84 | // Add an heap allocated object to the collector. 85 | void addObject(GCObject* o); 86 | 87 | // Remove a heap allocated object from the collector. 88 | void removeObject(GCObject* o); 89 | 90 | // Go through all objects in the heap, unmarking the live 91 | // objects and destroying the unreferenced ones. 92 | void sweep(bool verbose); 93 | 94 | // Number of live objects in heap 95 | int live(); 96 | }; 97 | 98 | #endif 99 | // Copyright (C) 2009 Chris Double. All Rights Reserved. 100 | // The original author of this code can be contacted at: chris.double@double.co.nz 101 | // 102 | // Redistribution and use in source and binary forms, with or without 103 | // modification, are permitted provided that the following conditions are met: 104 | // 105 | // 1. Redistributions of source code must retain the above copyright notice, 106 | // this list of conditions and the following disclaimer. 107 | // 108 | // 2. Redistributions in binary form must reproduce the above copyright notice, 109 | // this list of conditions and the following disclaimer in the documentation 110 | // and/or other materials provided with the distribution. 111 | // 112 | // THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 113 | // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 114 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 115 | // DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 116 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 117 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 118 | // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 119 | // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 120 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 121 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 122 | // 123 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | UNAME=$(shell uname -s) 2 | 3 | ifeq "$(UNAME)" "Darwin" 4 | INCLUDE=-I/opt/local/include 5 | LIB=-L/opt/local/lib 6 | endif 7 | 8 | INCLUDE= 9 | LIB= 10 | CFLAGS=-g 11 | 12 | all: libgc.a 13 | 14 | libgc.a: gc.o 15 | ar r libgc.a gc.o 16 | 17 | gc.o: gc.cpp gc.h 18 | g++ $(INCLUDE) $(CFLAGS) -c -o gc.o gc.cpp 19 | 20 | clean: 21 | rm gc.o 22 | rm libgc.a 23 | --------------------------------------------------------------------------------