diff -r 2b6904506469 -r a92afa7484fd jitcraft/Heap.h --- a/jitcraft/Heap.h Wed Jul 04 19:54:53 2012 -0400 +++ b/jitcraft/Heap.h Fri Jul 06 09:45:21 2012 -0400 @@ -1,4 +1,5 @@ -/* +/* vim: set ts=4 sw=4 tw=99 et: + * * Copyright (C) 2012 David Anderson * * This file is part of JITCraft. @@ -28,13 +29,67 @@ class Zone; -// Heap-allocated objects go here. Heaps are thread-local. +// Heap-allocated objects go here. Heaps are thread-local. The heap contains +// four spaces: +// +// LIFO Space: Used for objects that may be stack-allocated. +// New Space: Used for objects that are expected to be short-lived. +// Old Space: Used for objects that are expected to be long-lived, or that +// survive one collection. +// Large Space: Used for objects that are so large they should never be +// moved between spaces. +// +// The garbage collector is both incremental and generational. Marking is +// performed incrementally, interleaved with program execution. Minor +// collections are also performed to mitigate the potential necessity of +// major collections. +// +// MINOR COLLECTIONS (also called "scavenges") are usually performed when the +// new space reaches maximum capacity. During a minor collection, all live +// objects in the new space are moved into the old space. Then, the new space +// is reset such that it is empty. +// +// The new is split into contiguous halves. When both halves reach maximum +// capacity, a scavenge is performed on the older half. Thus, allocation is +// only ever performed in one half at a time, to give newer objects a chance +// to die. +// +// Scavenges are beneficial for two major reasons: +// (1) Allocation from the new space is just a pointer bump. +// (2) Only the root set and remembered sets need to visited. +// +// The "remembered set" is a list of all pointers that reach into the new +// space, but come from the Old or Large spaces. The remembered set is +// maintained via write barriers, and if it becomes full, entire chunks +// are marked as requiring traversal. +// +// The root and remembered sets must be visited twice: once to determine +// which objects in the new space are live, and again to update any +// references after the new space has been reclaimed. +// +// Live objects in the LIFO space are always deeply traversed for pointers +// into the new space, since it would be too difficult to maintain a working +// remembered set. +// +// MAJOR COLLECTIONS are performed periodically, when either a given memory +// threshold has been reached, or when requested by the host application. +// They are also performed if no memory can be allocated. +// +// Major collections are extremely slow; they require full heap traversal, +// which can take more than a second on very large heaps. However, they +// have the greatest chance at reclaiming all syntactically dead objects. +// +// SWEEPING is performed after major collections. The free space in between +// live objects is added to a free list. Tenured allocations are then +// performed in the free space, if possible. +// class Heap { Zone *zone_; HeapStack lifoSpace_; OldSpace mapSpace_; OldSpace oldSpace_; + LargeObjectSpace largeSpace_; Map *metaMap_; @@ -54,7 +109,8 @@ }; private: - Address newOldObject(size_t bytes); + inline Address newLargeObject(size_t bytes); + inline Address newOldObject(size_t bytes); inline Address newStackObject(size_t bytes); inline Address newObject(size_t bytes, Tenure pretenure); @@ -74,6 +130,9 @@ inline void unwindLifo(Address to) { lifoSpace_.unwind(to); } + + // Perform a full garbage collection. + void reclaim(); }; }