Updated with README and stuff.
This commit is contained in:
parent
27d16e33bd
commit
9635a253f5
|
@ -1,7 +1,6 @@
|
||||||
project("Collector")
|
project("Collector")
|
||||||
|
|
||||||
list(APPEND CMAKE_C_FLAGS "-std=c99 ${CMAKE_C_FLAGS} -g -ftest-coverage -fprofile-arcs")
|
list(APPEND CMAKE_CXX_FLAGS "${CXXMAKE_C_FLAGS} -std=c++1y -I../src/include/ -g")
|
||||||
|
|
||||||
add_executable(collector
|
add_executable(collector src/collector.cpp)
|
||||||
src/collector.c)
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
---
|
||||||
|
**WHAT:**
|
||||||
|
|
||||||
|
This is an example of Bob Nystrom's
|
||||||
|
"[Baby's First Garbage Collector](http://journal.stuffwithstuff.com/2013/12/08/babys-first-garbage-collector/),"
|
||||||
|
which I've been wanting to implement for a while in order to understand
|
||||||
|
it better. To make the problem harder (as I always do), I decided to
|
||||||
|
write it in C++, and to make it even more fun, I've implemented it using
|
||||||
|
the new Variant container from C++17.
|
||||||
|
|
||||||
|
**WHY:**
|
||||||
|
|
||||||
|
I've never written a garbage collector before. Now I know what it is
|
||||||
|
and how it works.
|
||||||
|
|
||||||
|
**DETAILS:**
|
||||||
|
|
||||||
|
The collector Nystrom wrote is a simple bi-color mark-and-sweep
|
||||||
|
collector for a singly threaded process with distinct pauses based upon
|
||||||
|
a straightforward memory usage heuristic. That heuristic is simply, "Is
|
||||||
|
the amount of memory currently in use twice as much as the last time we
|
||||||
|
garbage collected?" If the answer is yes, the collector runs and sweeps
|
||||||
|
up the stack.
|
||||||
|
|
||||||
|
Nystrom's code is highly readable, and I hope mine is as well. Because
|
||||||
|
I used Variant, my Object class has an internal Pair class, and then the
|
||||||
|
Variant is just \<int, Pair\>, where "Pair" is a pair of pointers to
|
||||||
|
other objects. The entirety of the VM is basically a stack of
|
||||||
|
singly-linked lists which either represents integers or collections of
|
||||||
|
integers in a Lisp-like structure.
|
||||||
|
|
||||||
|
The allocator creates two kinds of objects, then: pairs, and lists. A
|
||||||
|
pair is created by pushing two other objects onto the stack, then
|
||||||
|
calling `push()`, which pops them off the stack and replaces them with a
|
||||||
|
Pair object. The VM class has two methods, both named `push()`, one of
|
||||||
|
which pushes an integer, the other a pair. Since a pair is built from
|
||||||
|
objects on the stack, the Pair version takes no arguments, and since
|
||||||
|
C++14 and beyond have move semantics that Variant honors,
|
||||||
|
Variant\<Pair\> only constructs a single pair. Pretty nice. I was also
|
||||||
|
able to use both lambda-style and constructor-style visitors in my
|
||||||
|
Variant, which was a fun little bonus.
|
||||||
|
|
||||||
|
**NOTE:**
|
||||||
|
|
||||||
|
I have included the header files for the
|
||||||
|
[Mapbox version of Variant](https://github.com/mapbox/variant) since the
|
||||||
|
C++17 committee's standards haven't quite reached the general public and
|
||||||
|
the Variant implementation is still a subject of some debate. This
|
||||||
|
implementation looks straightforward enough and is a header-only
|
||||||
|
release. It works with both GCC 4.8.5 and Clang 3.8, and that's good
|
||||||
|
enough for me.
|
||||||
|
|
||||||
|
The Mapbox variant is BSD licensed, and a copy of the license is
|
||||||
|
included in the Include directory.
|
||||||
|
|
||||||
|
**BUILDING:**
|
||||||
|
|
||||||
|
From the base directory of the project:
|
||||||
|
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
make
|
||||||
|
|
||||||
|
And you should be able to run the basic tests. It's just one file.
|
|
@ -37,6 +37,7 @@ public:
|
||||||
unsigned char marked;
|
unsigned char marked;
|
||||||
Object *next;
|
Object *next;
|
||||||
Object(int v): marked(0), value(v) {}
|
Object(int v): marked(0), value(v) {}
|
||||||
|
// Variant<Pair> uses move semantics; this doesn't result in Pair being built twice.
|
||||||
Object(Object* head, Object* tail): marked(0), value(Pair(head, tail)) {}
|
Object(Object* head, Object* tail): marked(0), value(Pair(head, tail)) {}
|
||||||
|
|
||||||
class Pair {
|
class Pair {
|
||||||
|
@ -113,10 +114,10 @@ public:
|
||||||
|
|
||||||
/* The saddest fact: I went with using NULL as our end-of-stack
|
/* The saddest fact: I went with using NULL as our end-of-stack
|
||||||
discriminator rather than something higher-level, like an
|
discriminator rather than something higher-level, like an
|
||||||
Optional or Either-variant, because to use those I'd have to
|
Optional or Either-variant, because to use those I'd have to use
|
||||||
user recursion to sweep the interpreter's stack, which means
|
recursion to sweep the interpreter's stack, which means I'm at
|
||||||
I'm at the mercy of the C stack, complete with the cost of the
|
the mercy of the C stack, complete with the cost of the unwind at
|
||||||
unwind at the end. Bummer. */
|
the end. Bummer. */
|
||||||
|
|
||||||
/* I look at this and ask, WWHSD? What Would Herb Sutter Do? */
|
/* I look at this and ask, WWHSD? What Would Herb Sutter Do? */
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
Copyright (c) MapBox
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
- Redistributions in binary form must reproduce the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
- Neither the name "MapBox" nor the names of its contributors may be
|
||||||
|
used to endorse or promote products derived from this software without
|
||||||
|
specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
Loading…
Reference in New Issue